যদি স্টেটমেন্ট বা স্যুইচ করা হয় তবে লম্বা চেইনের পাশাপাশি এটি করার আরও বুদ্ধিমান কোনও উপায় আছে কি?


20

আমি একটি আইআরসি বট প্রয়োগ করছি যা একটি বার্তা পায় এবং আমি কোন বার্তাটি কল করতে হবে তা নির্ধারণ করতে সেই বার্তাটি যাচাই করছি। এটি করার আরও চতুর উপায় আছে? দেখে মনে হচ্ছে 20 কমান্ড পছন্দ করার পরে তাড়াতাড়ি হাতছাড়া হয়ে যাবে।

সম্ভবত এটি বিমূর্ত করার আরও ভাল উপায় আছে?

 public void onMessage(String channel, String sender, String login, String hostname, String message){

        if (message.equalsIgnoreCase(".np")){
//            TODO: Use Last.fm API to find the now playing
        } else if (message.toLowerCase().startsWith(".register")) {
                cmd.registerLastNick(channel, sender, message);
        } else if (message.toLowerCase().startsWith("give us a countdown")) {
                cmd.countdown(channel, message);
        } else if (message.toLowerCase().startsWith("remember am routine")) {
                cmd.updateAmRoutine(channel, message, sender);
        }
    }

14
কী ভাষা, তার ধরণের গুরুত্বপূর্ণ এই স্তরে গুরুত্বপূর্ণ।
mattnz

3
@ ম্যাট্টনজ জাভা-র সাথে পরিচিত কেউই তার সরবরাহিত কোড নমুনায় এটি সনাক্ত করতে পারবেন।
জওয়েন্টিং

6
@ জওয়েন্টিং: এটি সি # সিনট্যাক্স বৈধও, এবং আমি আরও বেশি ভাষা আছে বলে বাজি ধরছি।
ফ্রেসনেল

4
@ ফ্রেসনেল হ্যাঁ, তবে স্ট্রিংয়ের জন্য কি ঠিক একই স্ট্যান্ডার্ড এপিআই রয়েছে?
jwenting

3
@ জওয়েন্টিং: এটি কি প্রাসঙ্গিক? তবে তা সত্ত্বেও: কেউ বৈধ উদাহরণ তৈরি করতে পারে, যেমন একটি জাভা / সি # -Interop সহায়তা সহায়ক লাইব্রেরি, বা। নেট: ikvm.net এর জন্য জাভাটি দেখুন। ভাষা সর্বদা প্রাসঙ্গিক। প্রশ্নকর্তা সুনির্দিষ্ট ভাষা খুঁজছেন না, তিনি সিনট্যাক্স ত্রুটি করেছেন (ঘটনাক্রমে জাভাটিকে সি # তে রূপান্তর করেছেন), নতুন ভাষা দেখা দিতে পারে (বা বন্যের মধ্যে উঠে এসেছে, যেখানে ড্রাগন রয়েছে) - সম্পাদনা করুন : আমার আগের মন্তব্যগুলি ডিকির প্রতি ছিল, দুঃখিত।
ফ্রেসেল

উত্তর:


45

একটি প্রেরণ টেবিল ব্যবহার করুন । এটি একটি টেবিল যা জোড়া ("বার্তা অংশ", pointer-to-function) রয়েছে। প্রেরণকারীটি তখন এর মতো দেখতে পাবেন (সিউডো কোডে):

for each (row in dispatchTable)
{
    if(message.toLowerCase().startsWith(row.messagePart))
    {
         row.theFunction(message);
         break;
    }
}

(এর equalsIgnoreCaseআগে কোথাও বিশেষ কেস হিসাবে পরিচালনা করা যেতে পারে, বা দ্বিতীয় পরীক্ষার টেবিল সহ যদি আপনার সেই পরীক্ষাগুলির মধ্যে অনেকগুলি থাকে)।

অবশ্যই কি pointer-to-functionদেখতে হবে তা আপনার প্রোগ্রামিং ভাষার উপর নির্ভর করে। সি বা সি ++ এর উদাহরণ এখানে । জাভা বা সি # তে আপনি সম্ভবত সেই উদ্দেশ্যে ল্যাম্বডা এক্সপ্রেশন ব্যবহার করবেন বা কমান্ড প্যাটার্নটি ব্যবহার করে আপনি "পয়েন্টার-টু-ফাংশন" সিমুলেট করুন। বিনামূল্যে অনলাইন বই " উচ্চতর আদেশ পার্ল " পার্ল ব্যবহার করে প্রেরণ টেবিল সম্পর্কে একটি সম্পূর্ণ অধ্যায় রয়েছে।


4
যদিও এর সাথে সমস্যা হ'ল আপনি মিলে যাওয়া প্রক্রিয়াটি নিয়ন্ত্রণ করতে পারবেন না। ওপির উদাহরণে, তিনি equalsIgnoreCase"এখন খেলছেন" তবে toLowerCase().startsWithঅন্যদের জন্য ব্যবহার করেন।
মির্জিংক

5
@ মির্জিংক: আমি এটিকে "সমস্যা" হিসাবে দেখছি না, এটি কেবল বিভিন্ন উপকারিতা এবং কনসগুলির সাথে একটি পৃথক পদ্ধতি। আপনার সমাধানের "প্রো": স্বতন্ত্র কমান্ডগুলির স্বতন্ত্র মিলন প্রক্রিয়া থাকতে পারে। আমার "প্রো": কমান্ডগুলিকে তাদের নিজস্ব মিলে যাওয়ার পদ্ধতি সরবরাহ করতে হবে না। ওপিকে সিদ্ধান্ত নিতে হবে কোন সমাধানটি তার পক্ষে সবচেয়ে উপযুক্ত। যাইহোক, আমি আপনার উত্তর upvated।
ডক ব্রাউন

1
এফওয়াইআই - "পয়েন্টার টু ফাংশন" হ'ল একটি সি # ভাষার বৈশিষ্ট্য যা ডেলিগেটস বলে। ল্যাম্বদা হ'ল একটি অভিব্যক্তি বস্তু যা চারপাশে পাস করা যায় - আপনি কোনও ড্যাম্বেটকে কল করার মতো ল্যাম্বডাকে "কল" করতে পারবেন না।
ব্যবহারকারী 1068

1
toLowerCaseলুপ থেকে অপারেশন উত্তোলন ।
zwol

1
@ হারিসননগুইয়েন: আমি ডকসস.ওরাকল . com/ জাভাসে / টিউটোরিয়াল / জাভা / জাভা ওআউ / র পরামর্শ দিচ্ছি । তবে আপনি যদি জাভা 8 ব্যবহার না করে থাকেন তবে আপনি "ম্যাচগুলি" অংশটি ব্যতীত মিঙ্কের ইন্টারফেস সংজ্ঞাটি ব্যবহার করতে পারেন, এটি 100% সমতুল্য (এটি আমি কমান্ড প্যাটার্নটি ব্যবহার করে পয়েন্টার-টু ফাংশন সিমুলেট করে বোঝাতে চাইছিলাম) এবং ব্যবহারকারী 1068 এর মন্তব্যটি বিভিন্ন প্রোগ্রামিং ভাষায় একই ধারণার বিভিন্ন রূপের জন্য বিভিন্ন পদ সম্পর্কে একটি মন্তব্য মাত্র
ডক ব্রাউন

31

আমি সম্ভবত এরকম কিছু করতাম:

public interface Command {
  boolean matches(String message);

  void execute(String channel, String sender, String login,
               String hostname, String message);
}

তারপরে আপনার প্রতিটি কমান্ড এই ইন্টারফেসটি বাস্তবায়িত করতে এবং বার্তার সাথে মেলে যখন সত্য ফিরে আসতে পারে।

List<Command> activeCommands = new ArrayList<>();
activeCommands.add(new LastFMCommand());
activeCommands.add(new RegisterLastNickCommand());
// etc.

for (Command command : activeCommands) {
    if (command.matches(message)) {
        command.execute(channel, sender, login, hostname, message);
        break; // handle the first matching command only
    }
}

যদি বার্তাগুলিকে কখনও অন্য কোথাও বিশ্লেষণের প্রয়োজন হয় না (আমি ধরেছিলাম যে আমার উত্তরে) এটি আমার সমাধানটির পক্ষে প্রকৃত পক্ষে ভাল Commandকারণ এটি কখন নিজের কাছে ডাকা হবে তা যদি জানা থাকে self কমান্ডগুলির তালিকা বিশাল যদি এটি সামান্য ওভারহেড উত্পাদন করে তবে এটি সম্ভবত নগন্য।
jhr

1
এই প্যাটার্নটি কনসোল কমান্ড প্যারাডিজমটি দুর্দান্তভাবে ফিট করে, তবে কেবলমাত্র এটি ইভেন্ট কন্ডিশনের সাথে কমান্ড যুক্তিকে আলাদা করে দেয় এবং ভবিষ্যতে নতুন কমান্ড যুক্ত হওয়ার সম্ভাবনা রয়েছে। আমি মনে করি এটি লক্ষ করা উচিত যে এটি কোনও পরিস্থিতিতেই সমাধান নয় যেখানে আপনার দীর্ঘ শৃঙ্খলা রয়েছে ... অন্যথায়
নীল

"হালকা" কমান্ড প্যাটার্ন ব্যবহার করার জন্য +1! এটি লক্ষ করা উচিত যে আপনি নন-স্ট্রিংয়ের সাথে যখন কাজ করছেন আপনি উদাহরণস্বরূপ বুদ্ধিমান এনামগুলি ব্যবহার করতে পারেন যা তাদের যুক্তি কার্যকর করতে জানেন। এমনকি এটি আপনাকে লুপটি সংরক্ষণ করে।
সর্বশেষ ফ্রি ডাকনাম

3
লুপের পরিবর্তে, আমরা এটিকে মানচিত্র হিসাবে ব্যবহার করতে পারি যদি আপনি কমান্ডকে একটি বিমূর্ত শ্রেণি তৈরি করেন যা ওভাররাইড করে equalsএবং hashCodeকমান্ডের প্রতিনিধিত্বকারী স্ট্রিংয়ের সাথে একই হয়
ক্রুনচার

এটি দুর্দান্ত এবং বুঝতে সহজ। পরামর্শের জন্য ধন্যবাদ. এটি ঠিক ঠিক আমি যা খুঁজছিলাম এবং ভবিষ্যতের আদেশগুলি যোগ করার জন্য এটি পরিচালনাযোগ্য বলে মনে হচ্ছে।
হ্যারিসন এনগুইন

15

আপনি জাভা ব্যবহার করছেন - সুতরাং এটি সুন্দর করুন ;-)

আমি সম্ভবত টিকা ব্যবহার করে এটি করব:

  1. একটি কাস্টম পদ্ধতি টীকা তৈরি করুন Create

    @IRCCommand( String command, boolean perfectmatch = false )
  2. ক্লাসে সমস্ত প্রাসঙ্গিক পদ্ধতিতে টীকা যুক্ত করুন উদাহরণস্বরূপ

    @IRCCommand( command = ".np", perfectmatch = true )
    doNP( ... )
  3. আপনার কনস্ট্রাক্টরে আপনার ক্লাসের সমস্ত টিকাপ্রাপ্ত পদ্ধতি থেকে পদ্ধতিগুলির একটি হ্যাশম্যাপ তৈরি করতে প্রতিচ্ছবিগুলি ব্যবহার করুন:

    ...
    for (Method m : getDeclaredMethods()) {
    if ( isAnnotationPresent... ) {
        commandList.put(m.getAnnotation(...), m);
        ...
  4. আপনার onMessageপদ্ধতিতে, commandListপ্রতিটি স্ট্রিংয়ের সাথে ম্যাচ করার চেষ্টা করে এবং method.invoke()যেখানে এটি ফিট করে সেখানে কল করার চেষ্টা করুন lo

    for ( @IRCCommand a : commanMap.keyList() ) {
        if ( cmd.equalsIgnoreCase( a.command )
             || ( cmd.startsWith( a.command ) && !a.perfectMatch ) {
            commandMap.get( a ).invoke( this, cmd );

তিনি জাভা ব্যবহার করছেন তা পরিষ্কার নয়, যদিও এটি একটি মার্জিত সমাধান।
নীল

আপনি ঠিক বলেছেন - কোডটি দেখতে অনেকটা গ্রহ-অটো-ফর্ম্যাট করা জাভা-কোডের মতো লাগছিল ... তবে আপনি সি # এবং সি ++ এর মাধ্যমেও কিছু চালাক ম্যাক্রোসের সাথে টীকাগুলি সিমুলেশন করতে পারেন
ফ্যালকো

এটি জাভা খুব ভাল হতে পারে, তবে ভবিষ্যতে, আমি আপনাকে ভাষা-নির্দিষ্ট সমাধানগুলি এড়াতে পরামর্শ দিই যদি ভাষা স্পষ্টভাবে নির্দেশিত না হয়। শুধু বন্ধুত্বপূর্ণ পরামর্শ।
নীল

এই সমাধানের জন্য ধন্যবাদ - আপনি ঠিক বলেছেন যে আমি প্রদত্ত কোডটিতে জাভা ব্যবহার করছি যদিও আমি নির্দিষ্ট করে নেই, এই চেহারাটি সত্যিই দুর্দান্ত এবং আমি এটির একটি শট দেওয়ার ব্যাপারে নিশ্চিত হব। দুঃখিত আমি দুটি সেরা উত্তর নিতে পারবেন না!
হ্যারিসন এনগুইন

5

আপনি যদি কোনও ইন্টারফেস সংজ্ঞায়িত করেন, তবে একটি IChatBehaviourপদ্ধতি বলে Executeযার একটি messageএবং একটি cmdঅবজেক্ট নেয় :

public Interface IChatBehaviour
{
    public void execute(String message, CMD cmd);
}

আপনার কোডে, আপনি তারপরে এই ইন্টারফেসটি বাস্তবায়ন করুন এবং আপনি যে আচরণগুলি চান তা নির্ধারণ করুন:

public class RegisterLastNick implements IChatBehaviour
{
    public void execute(String message, CMD cmd)
    {
        if (message.toLowerCase().startsWith(".register"))
        {
            cmd.registerLastNick(channel, sender, message);
        }
    }
}

এবং তাই বাকি জন্য।

আপনার প্রধান শ্রেণিতে আপনার তখন আচরণের একটি তালিকা রয়েছে ( List<IChatBehaviour>) যা আপনার আইআরসি বট প্রয়োগ করে। এরপরে আপনি আপনার ifবক্তব্যগুলিকে এরকম কিছু দিয়ে প্রতিস্থাপন করতে পারেন:

for(IChatBehaviour behaviour : this.behaviours)
{
    behaviour.execute(message, cmd);
}

উপরেরটিতে আপনার কোডের পরিমাণ হ্রাস করা উচিত। উপরোক্ত পদ্ধতির সাহায্যে বট শ্রেণি নিজেই পরিবর্তন না করে আপনার বট শ্রেণিতে অতিরিক্ত আচরণ সরবরাহ করার অনুমতি দেওয়া হবে (যেমন অনুযায়ী Strategy Design Pattern)।

আপনি যদি একবারে কেবল একটি আচরণে আগুন জ্বালাতে চান তবে আপনি executeউত্পাদনের পদ্ধতির স্বাক্ষর পরিবর্তন করতে পারেন true(আচরণটি চালিত হয়েছে) বা false(আচরণটি আগুন দেয়নি) এবং উপরের লুপটিকে এই জাতীয় কিছু দিয়ে প্রতিস্থাপন করতে পারেন:

for(IChatBehaviour behaviour : this.behaviours)
{
    if(behaviour.execute(message, cmd))
    { 
         break;
    }
}

উপরোক্ত বাস্তবায়ন এবং আরম্ভ করার জন্য আরও ক্লান্তিকর হবে যেহেতু আপনাকে সমস্ত অতিরিক্ত ক্লাস তৈরি এবং পাস করা দরকার তবে এটি আপনার বটটিকে সহজেই বর্ধনযোগ্য এবং সংশোধনযোগ্য করে তুলবে কারণ আপনার সমস্ত আচরণের ক্লাসগুলি একে অপরের থেকে আলাদা হবে এবং আশা করা যায় যে একে অপর থেকে স্বতন্ত্র।


1
কোথায় গেল if? অর্থাৎ, আপনি কীভাবে কোনও আদেশ আদেশের জন্য কোনও আচরণ সম্পাদন করবেন তা স্থির করবেন?
মির্জিংক

2
@ মির্জিংক: দুঃখিত আমার খারাপ। মৃত্যুদণ্ড কার্যকর করা উচিত বা না করার সিদ্ধান্তটি আচরণকে দেওয়া হয় (আমি ভুলভাবে ifআচরণের অংশটি বাদ দিয়েছি )।
npinti

আমি মনে করি যে প্রদত্ত IChatBehaviourকোনও প্রদত্ত আদেশটি পরিচালনা করতে পারে কিনা সে সম্পর্কে আমি চেকটিকে অগ্রাধিকার দিই , কারণ এটি কলকারীকে এর সাথে আরও কিছু করার অনুমতি দেয়, যেমন কোনও আদেশের সাথে মিল না থাকলে প্রক্রিয়া ত্রুটি যেমন এটি কেবলমাত্র ব্যক্তিগত পছন্দ। যদি এটির প্রয়োজন না হয়, তবে অযথা কোড জটিল করার কোনও বিন্দু নেই।
নীল

আপনি এখনও এটা চালানো আদেশ, যা এখনও Ifs বা বৃহদায়তন সুইচ বিবৃতি একই দীর্ঘ শৃঙ্খল হবে সঠিক ক্লাসের নিদর্শনের সঙ্গে জেনারেট করতে একটি উপায় প্রয়োজন চাই ...
jwenting

1

"বুদ্ধিমান" তিনটি জিনিস হতে পারে (কমপক্ষে):

উচ্চতর পারফরম্যান্স

প্রেরণ সারণী (এবং এর সমতুল্য) পরামর্শটি একটি ভাল। এই ধরণের টেবিলটিকে "ক্যানড অ্যাড; ডিট এনেস ট্রাইও করতে পারে না" এর জন্য গত বছরগুলিতে "ক্যাডেট" নামে পরিচিত। তবে, কীভাবে বললেন সারণীটি পরিচালনা করতে পারে সে সম্পর্কে একজন নবজাতক রক্ষণাবেক্ষণকারীকে সহায়তা করার জন্য একটি মন্তব্য বিবেচনা করুন।

Maintainability

"এটিকে সুন্দর করুন" কোনও নিষ্ক্রিয় উপদেশ নয়।

এবং, প্রায়শই উপেক্ষা করা হয় ...

স্থিতিস্থাপকতা

টোএলওয়ারকেস ব্যবহারের ফলে এমন সমস্যা রয়েছে যে ম্যাজিকুল এবং মিনিস্কুলের মধ্যে পরিবর্তন করার সময় কিছু ভাষার কিছু পাঠ্যকে অবশ্যই বেদনাদায়ক পুনর্গঠন করতে হবে। দুর্ভাগ্যক্রমে, টুপারসেসের জন্য একই সমস্যাগুলি বিদ্যমান। শুধু সচেতন হতে হবে।


0

আপনি সমস্ত কমান্ড একই ইন্টারফেস প্রয়োগ করতে পারে। তারপরে একটি বার্তা বিশ্লেষক আপনাকে যথাযথ কমান্ডটি ফিরিয়ে দিতে পারে যা আপনি কেবলমাত্র সম্পাদন করবেন।

public interface Command {
    public void execute(String channel, String message, String sender) throws Exception;
}

public class MessageParser {
    public Command parseCommandFromMessage(String message) {
        // TODO Put your if/switch or something more clever here
        // e.g. return new CountdownCommand();
    }
}

public class Whatever {
    public void onMessage(String channel, String sender, String login, String hostname, String message) {
        Command c = new MessageParser().parseCommandFromMessage(message);
        c.execute(channel, message, sender);
    }
}

এটি দেখতে আরও কোডের মতো দেখাচ্ছে। হ্যাঁ, কোন আদেশটি কার্যকর করতে হবে তা জানতে আপনাকে বার্তাটি বিশ্লেষণ করতে হবে তবে এখন এটি একটি সঠিকভাবে সংজ্ঞায়িত বিন্দুতে। এটি অন্য কোথাও পুনরায় ব্যবহার করা যেতে পারে। (আপনি মেসেজ পার্সার ইনজেকশন করতে চাইতে পারেন তবে এটি অন্য একটি বিষয়। এছাড়াও, আপনি কতজন তৈরি হওয়ার আশা করছেন তার উপর নির্ভর করে ফ্লাইওয়েট প্যাটার্ন কমান্ডগুলির পক্ষে ভাল ধারণা হতে পারে))


আমি মনে করি এটি ডিউপলিং এবং প্রোগ্রাম সংস্থার পক্ষে ভাল, যদিও আমি মনে করি না যে এটি যদি সরাসরি ... আরও কিছু বিবৃতি দিয়ে থাকে তবে খুব বেশি থাকার সমস্যাটিকে সরাসরি সমাধান করে।
নীল

0

আমি যা করবো তা হ'ল:

  1. আপনার যে কমান্ডগুলি রয়েছে সেগুলিকে দলবদ্ধ করুন। (আপনার এখনই কমপক্ষে 20 আছে)
  2. প্রথম স্তরে, গোষ্ঠী অনুসারে শ্রেণিবদ্ধকরণ করুন, যাতে আপনার ব্যবহারকারীর নাম সম্পর্কিত কমান্ড, গানের কমান্ড, গণনা কমান্ড ইত্যাদি থাকে have
  3. তারপরে আপনি প্রতিটি গ্রুপের পদ্ধতিতে যান, এবার আপনি আসল কমান্ড পাবেন।

এটি এটিকে আরও পরিচালনাযোগ্য করে তুলবে। 'অন্যথায়' এর সংখ্যা খুব বেশি বেড়ে গেলে আরও উপকার পাবেন।

অবশ্যই, কখনও কখনও এই 'অন্যথায়' থাকা বড় সমস্যা হবে না। আমার মনে হয় 20 টি খারাপ না।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.