একাধিক স্যুইচ কেস সহ একটি অ্যাপ্লিকেশন রিফ্যাক্টর কিভাবে?


10

আমার কাছে একটি অ্যাপ্লিকেশন রয়েছে যা একটি পূর্ণসংখ্যা ইনপুট হিসাবে গ্রহণ করে এবং ইনপুটটির ভিত্তিতে বিভিন্ন শ্রেণীর স্থিত পদ্ধতিগুলি কল করে। প্রতিবার নতুন নম্বর যুক্ত হওয়ার সাথে সাথে আমাদের অন্য কেস যুক্ত করতে হবে এবং আলাদা শ্রেণীর একটি পৃথক স্ট্যাটিক পদ্ধতি কল করতে হবে। স্যুইচটিতে এখন 50 টি কেস রয়েছে এবং প্রতিবার আমার আর একটি কেস যুক্ত করা দরকার, আমি কাঁপছি। এই কাজ করতে একটি ভাল উপায় আছে কি.

আমি কিছু চিন্তাভাবনা করেছি এবং এই ধারণাটি নিয়ে এসেছি। আমি কৌশল প্যাটার্ন ব্যবহার। স্যুইচ কেস হওয়ার পরিবর্তে আমার কাছে কৌশল অবজেক্টের মানচিত্র রয়েছে যার কীটি ইনপুট পূর্ণসংখ্যা। একবার পদ্ধতিটি শুরু হয়ে গেলে এটি বস্তুর সন্ধান করবে এবং বস্তুর জন্য জেনেরিক পদ্ধতিটি কল করবে। এইভাবে আমি সুইচ কেস কনস্ট্রাক্ট ব্যবহার এড়াতে পারি।

আপনি কি মনে করেন?


2
বর্তমান কোডটি নিয়ে আসল সমস্যাটি কী?
ফিলিপ কেন্ডাল

এই পরিবর্তনগুলির মধ্যে একটি যখন আপনাকে করতে হবে তখন কী হবে? switchআপনার জটিল সিস্টেমে কি আপনাকে কেস যুক্ত করতে হবে এবং প্রাক-বিদ্যমান পদ্ধতিটি কল করতে হবে, বা আপনাকে কী পদ্ধতি এবং এর কল উভয়ই আবিষ্কার করতে হবে?
কিলিয়ান ফট

@ কিলিয়ানফথ আমি এই প্রকল্পটি রক্ষণাবেক্ষণ বিকাশকারী হিসাবে উত্তরাধিকার সূত্রে পেয়েছি এবং এখনও কোনও পরিবর্তন করতে হয়নি। আমি যাইহোক শীঘ্রই পরিবর্তনগুলি করব, তাই এখনই রিফ্যাক্টর করতে চাই। তবে আপনার প্রশ্নের উত্তর দেওয়ার জন্য, হ্যাঁ উত্তরটি।
কৌশিক চক্রবর্তী

2
আমার মনে হয় আপনার যা চলছে তার একটি ঘনীভূত উদাহরণ প্রদর্শন করা দরকার।
হোস্টনাম

1
@ কৌশিকচক্রবর্তী: তারপরে স্মৃতি থেকে একটি উদাহরণ তৈরি করুন। এমন পরিস্থিতি রয়েছে যেখানে 250+ কেস উবার-স্যুইচ যথাযথ হয় এবং এমন কিছু ক্ষেত্রে রয়েছে যেখানে স্যুইচ খারাপ হয় তা যত কম কেসই থাকুক না কেন। শয়তান বিশদে রয়েছে এবং আমাদের কোনও বিবরণ নেই।
whatsisname

উত্তর:


13

স্যুইচটিতে এখন 50 টি কেস রয়েছে এবং প্রতিবার আমার আর একটি কেস যুক্ত করা দরকার, আমি কাঁপছি।

আমি পলিমারফিজম পছন্দ করি। আমি সলিড ভালবাসি। আমি খাঁটি অবজেক্ট ওরিয়েন্টেড প্রোগ্রামিং পছন্দ করি। এগুলি দেওয়া খারাপ প্রতিক্রিয়া দেখতে আমি ঘৃণা করি কারণ তারা কুকর্মের সাথে প্রয়োগ হয়।

আপনি কৌশলটি রিফ্যাক্টরিং জন্য ভাল মামলা করেন নি। রিফ্যাক্টরিংয়ের একটি নাম রয়েছে। একে Polymorphism সহ শর্তাধীন প্রতিস্থাপন বলা হয় ।

আমি c2.com থেকে আপনার জন্য কিছু প্রাসঙ্গিক পরামর্শ পেয়েছি :

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

আপনার 50 টি কেস সহ একটি স্যুইচ রয়েছে এবং আপনার বিকল্পটি 50 টি অবজেক্ট তৈরি করা produce ওহ এবং অবজেক্ট কনস্ট্রাকশন কোডের 50 টি লাইন। এটি অগ্রগতি নয়। কেন না? কারণ এই রিফ্যাক্টরিং 50 থেকে সংখ্যা হ্রাস করতে কিছুই করে না you আপনি যখন অন্য কোনও জায়গায় একই ইনপুটটিতে অন্য একটি সুইচ স্টেটমেন্ট তৈরি করতে হবে তখন আপনি এই রিফ্যাক্টরিংটি ব্যবহার করেন। এই রিফ্যাক্টরিং সাহায্য করে কারণ এটি 100 টি 50 এ পরিণত হয়েছে।

এতক্ষণ আপনি যদি "স্যুইচ" হিসাবে উল্লেখ করেন তবে এটি আপনার একমাত্র থাকে তবে আমি এটি প্রস্তাব দিই না। এখন রিফ্যাক্টরিং থেকে আসার একমাত্র সুবিধা হ'ল এটি কিছু গোফবল আপনার 50 কেস স্যুইচটি অনুলিপি করে পেস্ট করবে এমন সম্ভাবনা হ্রাস করে।

আমি যা প্রস্তাব দিচ্ছি তা 50 টি সাধারণ বিষয়গুলির ক্ষেত্রে খুব ঘনিষ্ঠভাবে পর্যবেক্ষণ করা হচ্ছে যা বাস্তবায়ন করা যায়। মানে 50? সত্যি? আপনি কি নিশ্চিত যে আপনার অনেকগুলি মামলা দরকার? আপনি এখানে অনেক কিছু করার চেষ্টা করছেন।


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

2
উচ্চ সংহতি লঙ্ঘন না করে আমি 50 টি পেতে পারি এবং জিনিসগুলিকে স্বয়ংসম্পূর্ণ রাখতে পারি। আমি কেবল একটি সংখ্যা দিয়ে এটি করতে পারি না। আমার একটি 2, 5 এবং অন্য 5 লাগবে why এজন্য এটিকে ফ্যাক্টরিং আউট বলা হয়। সিরিয়াসলি, আপনার পুরো আর্কিটেকচারটি দেখুন এবং দেখুন যে আপনি যে 50 টিরকম নরকের মধ্যে রয়েছেন তার কোনও পথ খুঁজে বের করতে পারেন না Ref রিফ্যাক্টরিং খারাপ সিদ্ধান্তগুলি পূর্বাবস্থায় ফেলার বিষয়ে। তাদের নতুন ফর্ম স্থায়ী না।
candied_orange

এখন, আপনি যদি এই রিফ্যাক্টরিংটি ব্যবহার করে 50 টি হ্রাস করার কোনও উপায় দেখতে পান তবে এটির জন্য যান। ডক ব্রাউনসের ধারণাটি উপকারের জন্য: মানচিত্রের মানচিত্রে দুটি কী লাগতে পারে। আমার মনে হয় কিছু।
candied_orange

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

@ কনডিয়েড "আপনি যখন এই রিপ্যাক্টরিংটি ব্যবহার করেন তখন আপনি একই ইনপুটটিতে অন্য কোথাও অন্য একটি সুইচ স্টেটমেন্ট তৈরি করতে হবে বলে মনে করেন" "আপনি কী এটিকে ব্যাখ্যা করতে পারবেন? আমার যেমন একটি মামলা রয়েছে যেখানে আমার সুইচ কেস রয়েছে তবে বিভিন্ন স্তরে যেমন আমাদের রয়েছে প্রকল্পের প্রথম অনুমোদন, বৈধকরণ, সিআরইউডি পদ্ধতিগুলি পরে দাও। সুতরাং প্রতিটি স্তরের একই ইনপুট অর্থাৎ একটি পূর্ণসংখ্যার উপর স্যুইচ কেস থাকে তবে বিভিন্ন ফাংশন যেমন auth, বৈধ। সুতরাং আমরা কি প্রতিটি ধরণের এক শ্রেণি তৈরি করতে পারি যার বিভিন্ন পদ্ধতি রয়েছে? "একই ইনপুটটিতে একই স্যুইচটি পুনরাবৃত্তি করে" আপনি যা বলার চেষ্টা করছেন তা কি আমাদের ক্ষেত্রে খাপ খায়?
সিদ্ধার্থ ত্রিখা

9

একাকী কৌশল অবজেক্টের একটি মানচিত্র, যা আপনার কোডের কিছু ফাংশনে সূচনা করা হয়েছে, যেখানে আপনার কোড দেখতে বেশ কয়েকটি লাইনের মত রয়েছে

     myMap.Add(1,new Strategy1());
     myMap.Add(2,new Strategy2());
     myMap.Add(3,new Strategy3());

আপনার এবং আপনার সহকর্মীদের আরও অভিন্ন পদ্ধতিতে আলাদা ক্লাসে ডেকে আনা ফাংশন / কৌশলগুলি বাস্তবায়নের প্রয়োজন (যেহেতু আপনার কৌশলগত বিষয়গুলি সকলকে একই ইন্টারফেস প্রয়োগ করতে হবে)। এই জাতীয় কোডটি প্রায়শই এর চেয়ে কিছুটা বেশি বিস্তৃত

     case 1:
          MyClass1.Doit1(someParameters);
          break;
     case 2:
          MyClass2.Doit2(someParameters);
          break;
     case 3:
          MyClass3.Doit3(someParameters);
          break;

যাইহোক, এটি যখনই নতুন নম্বর যুক্ত করার প্রয়োজন হয় তখনই এই কোড ফাইলটি সম্পাদনার ভার থেকে আপনাকে মুক্তি দেয় না। এই পদ্ধতির আসল সুবিধাগুলি একটি আলাদা a

  • মানচিত্রের সূচনাটি এখন প্রেরণ কোড থেকে পৃথক হয়ে যায় যা প্রকৃতপক্ষে একটি নির্দিষ্ট সংখ্যার সাথে সম্পর্কিত ফাংশনটিকে কল করে এবং পরবর্তীকালে সেই 50 টি পুনরাবৃত্তি আর থাকে না , এটি দেখতে দেখতে ঠিক দেখতে হবে myMap[number].DoIt(someParameters)। সুতরাং যখনই কোনও নতুন সংখ্যা আসবে এবং ওপেন-ক্লোজড নীতি অনুযায়ী প্রয়োগ করা যেতে পারে তখন এই প্রেরণ কোডটি স্পর্শ করার দরকার নেই। তদ্ব্যতীত, আপনি যখন প্রেরণ কোড নিজেই প্রসারিত করতে হবে এমন প্রয়োজনীয়তাগুলি পেয়ে গেলে, আপনাকে আর 50 টি স্থান পরিবর্তন করতে হবে না, কেবলমাত্র একটি।

  • মানচিত্রের বিষয়বস্তু রান-টাইমে নির্ধারিত হয় (যখন স্যুইচ কনস্ট্রাক্টের বিষয়বস্তু সংকলন-সময়ের আগে নির্ধারিত হয়), সুতরাং এটি আপনাকে সূচনা যুক্তিকে আরও নমনীয় বা প্রসারিত করার সুযোগ দেয়।

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


যদিও আমি পলিমারফিজমের সাথে প্রতিটি স্যুইচকে অন্ধভাবে প্রতিস্থাপন করতে অনিচ্ছুক যখনই আমি বলব যে ডক ব্রাউন এখানে যেভাবে মানচিত্র ব্যবহার করেছে সেটি অতীতে আমার জন্য খুব ভাল কাজ করেছে। আপনি একই ইন্টারফেস বাস্তবায়ন হলে দয়া করে প্রতিস্থাপন Doit1, Doit2এক সঙ্গে ইত্যাদির Doitপদ্ধতি বিভিন্ন বাস্তবায়নের রয়েছে।
candied_orange

কী হিসাবে ব্যবহৃত ইনপুট চিহ্নের ধরণের উপর যদি আপনার নিয়ন্ত্রণ থাকে তবে আপনি ইনপুট চিহ্নের doTheThing()একটি পদ্ধতি তৈরি করে আরও এক ধাপ এগিয়ে যেতে পারেন । তারপরে আপনাকে মানচিত্রটি বজায় রাখার দরকার নেই।
কেভিন ক্রামউইডে

1
@ কেভিন ক্রামউইদে: আপনার পরামর্শের অর্থ হল পূর্ণসংখ্যার প্রতিস্থাপন হিসাবে কৌশলটি কেবল প্রোগ্রামটি পাস করা। যাইহোক, প্রোগ্রামটি যখন কোনও বাহ্যিক ডেটা উত্স থেকে ইনপুট হিসাবে কোনও পূর্ণসংখ্যার গ্রহণ করে, সিস্টেমের কমপক্ষে একটি স্থানে ইন্টিজার থেকে সম্পর্কিত কৌশলটিতে ম্যাপিং করতে হবে ।
ডক ব্রাউন

ডক ব্রাউনয়ের পরামর্শকে প্রসারিত করা: আপনি এমন একটি কারখানাও তৈরি করতে পারেন যাতে কৌশল অবজেক্ট তৈরির জন্য যুক্তি থাকতে পারে, আপনি যদি এই পথে যাওয়ার সিদ্ধান্ত নেন। এটি বলেছিল, ক্যান্ডিডআরঞ্জের দেওয়া উত্তরটি আমার কাছে সবচেয়ে বেশি অর্থবোধ করে।
ভ্লাদিমির স্টোকিক

"ডকব্রাউন" এটাই আমি পেয়ে যাচ্ছিলাম "যদি আপনার ইনপুট প্রতীকের ধরণের উপর নিয়ন্ত্রণ থাকে"।
কেভিন ক্রামউইডে

0

আমি কৌশলের রূপরেখা পক্ষে জোরালোভাবে am @DocBrown দ্বারা উত্তর

আমি উত্তরের একটি উন্নতি প্রস্তাব করতে যাচ্ছি।

কল

 myMap.Add(1,new Strategy1());
 myMap.Add(2,new Strategy2());
 myMap.Add(3,new Strategy3());

বিতরণ করা যেতে পারে। অন্য কৌশল যুক্ত করতে আপনাকে একই ফাইলটিতে ফিরে যেতে হবে না, যা ওপেন-ক্লোজড নীতিটি আরও ভালভাবে মেনে চলে।

বলুন আপনি Strategy1কৌশল 1.cpp ফাইলটিতে প্রয়োগ করেন। এটিতে আপনার নীচের কোডের ব্লক থাকতে পারে।

namespace Strategy1_Impl
{
   struct Initializer
   {
      Initializer()
      {
         getMap().Add(1, new Strategy1());
      }
   };
}
using namespace Strategy1_Impl;

static Initializer initializer;

আপনি প্রতিটি স্ট্যাটাইএনএনপিপি ফাইলগুলিতে একই কোডটি পুনরাবৃত্তি করতে পারেন। আপনি দেখতে পাচ্ছেন যে এটি প্রচুর পুনরাবৃত্তি কোড হবে। কোড সদৃশতা হ্রাস করতে, আপনি একটি টেম্পলেট ব্যবহার করতে পারেন যা কোনও ফাইলের মধ্যে রাখা যেতে পারে যা সমস্ত Strategyক্লাসে অ্যাক্সেসযোগ্য ।

namespace StrategyHelper
{
   template <int N, typename StrategyType> struct Initializer
   {
      Initializer()
      {
         getMap().Add(N, new StrategyType());
      }
   };
}

এর পরে, কৌশল 1.cpp এ আপনাকে ব্যবহার করতে হবে কেবলমাত্র:

static StrategyHelper::Initializer<1, Strategy1> initializer;

কৌশল N.cpp এ সম্পর্কিত লাইনটি হ'ল:

static StrategyHelper::Initializer<N, StrategyN> initializer;

আপনি কংক্রিট কৌশল ক্লাসগুলির জন্য শ্রেণিক টেম্পলেট ব্যবহার করে টেমপ্লেটগুলির ব্যবহারকে অন্য স্তরে নিয়ে যেতে পারেন।

class Strategy { ... };

template <int N> class ConcreteStrategy;

এবং তারপরে, পরিবর্তে Strategy1, ব্যবহার করুন ConcreteStrategy<1>

template <> class ConcreteStrategy<1> : public Strategy { ... };

এইগুলিতে নিবন্ধকরণ করতে সহায়ক শ্রেণি পরিবর্তন করুন Strategy:

namespace StrategyHelper
{
   template <int N> struct Initializer
   {
      Initializer()
      {
         getMap().Add(N, new ConcreteStrategy<N>());
      }
   };
}

স্ট্র্যাটেজি 1 সিপিতে কোডটি এতে পরিবর্তন করুন:

static StrategyHelper::Initializer<1> initializer;

স্ট্র্যাটেজিএন সিপ্পিতে কোডটি এতে পরিবর্তন করুন:

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