CodeGym /Java Blog /এলোমেলো /কৌশল ডিজাইন প্যাটার্ন
John Squirrels
লেভেল 41
San Francisco

কৌশল ডিজাইন প্যাটার্ন

এলোমেলো দলে প্রকাশিত
ওহে! আজকের পাঠে, আমরা কৌশল প্যাটার্ন সম্পর্কে কথা বলব। পূর্ববর্তী পাঠে, আমরা ইতিমধ্যেই উত্তরাধিকার ধারণার সাথে সংক্ষিপ্তভাবে পরিচিত হয়েছি। যদি আপনি ভুলে যান, আমি আপনাকে মনে করিয়ে দেব যে এই শব্দটি একটি সাধারণ প্রোগ্রামিং টাস্কের একটি আদর্শ সমাধানকে বোঝায়। CodeGym এ, আমরা প্রায়ই বলি যে আপনি প্রায় যেকোনো প্রশ্নের উত্তর গুগল করতে পারেন। এটি এই কারণে যে আপনার কাজ, যাই হোক না কেন, সম্ভবত ইতিমধ্যে অন্য কেউ সফলভাবে সমাধান করেছে। প্যাটার্নগুলি হল সবচেয়ে সাধারণ কাজগুলির জন্য চেষ্টা করা এবং সত্য সমাধান, বা সমস্যাযুক্ত পরিস্থিতি সমাধানের পদ্ধতি। এগুলি হল "চাকার" মতো যেগুলি আপনার নিজের থেকে পুনরায় উদ্ভাবনের প্রয়োজন নেই, তবে কীভাবে এবং কখন সেগুলি ব্যবহার করতে হবে তা আপনাকে জানতে হবে :) প্যাটার্নগুলির আরেকটি উদ্দেশ্য হল অভিন্ন স্থাপত্যের প্রচার করা৷ অন্য কারো কোড পড়া কোন সহজ কাজ নয়! সবাই আলাদা আলাদা কোড লেখে, কারণ একই কাজ অনেক উপায়ে সমাধান করা যেতে পারে। কিন্তু প্যাটার্নের ব্যবহার বিভিন্ন প্রোগ্রামারকে কোডের প্রতিটি লাইনে (এমনকি প্রথমবার দেখার সময়ও!) না দেখেই প্রোগ্রামিং লজিক বুঝতে সাহায্য করে। নকশা প্যাটার্ন: কৌশল - 2কল্পনা করুন যে আমরা একটি প্রোগ্রাম লিখছি যা সক্রিয়ভাবে কনভেয়েন্স অবজেক্টের সাথে কাজ করবে। এটা আসলে আমাদের প্রোগ্রাম ঠিক কি ব্যাপার না. আমরা একটি কনভেয়েন্স প্যারেন্ট ক্লাস এবং তিনটি চাইল্ড ক্লাস সহ একটি ক্লাস হায়ারার্কি তৈরি করেছি: Sedan , Truck এবং F1Car

public class Conveyance {

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {

       System.out.println("Braking!");
   }
}

public class Sedan extends Conveyance {
}

public class Truck extends Conveyance {
}

public class F1Car extends Conveyance {
}
তিনটি শিশু শ্রেণিই অভিভাবকের কাছ থেকে দুটি আদর্শ পদ্ধতির উত্তরাধিকারী: go() এবং stop() । আমাদের কর্মসূচী খুবই সহজ: আমাদের গাড়ি শুধুমাত্র এগিয়ে যেতে পারে এবং ব্রেক প্রয়োগ করতে পারে। আমাদের কাজ অব্যাহত রেখে, আমরা গাড়িগুলিকে একটি নতুন পদ্ধতি দেওয়ার সিদ্ধান্ত নিয়েছি: fill() (অর্থাৎ, "গ্যাস ট্যাঙ্ক পূরণ করুন")। আমরা কনভেয়েন্স প্যারেন্ট ক্লাসে এটি যোগ করেছি:

public class Conveyance {

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {

       System.out.println("Braking!");
   }
  
   public void fill() {
       System.out.println("Refueling!");
   }
}
এত সহজ পরিস্থিতিতে কি সত্যিই সমস্যা দেখা দিতে পারে? আসলে, তারা ইতিমধ্যেই আছে... নকশা প্যাটার্ন: কৌশল - 3

public class Stroller extends Conveyance {

   public void fill() {
      
       // Hmm... This is a stroller for children. It doesn't need to be refueled :/
   }
}
আমাদের প্রোগ্রামে এখন একটি কনভেয়েন্স (একটি বেবি স্ট্রলার) রয়েছে যা সাধারণ ধারণার সাথে সুন্দরভাবে মানায় না। এটিতে প্যাডেল থাকতে পারে বা রেডিও-নিয়ন্ত্রিত হতে পারে, তবে একটি জিনিস নিশ্চিতভাবে নিশ্চিত - এতে গ্যাস ঢালার কোনও জায়গা থাকবে না। আমাদের শ্রেণী শ্রেণিবিন্যাসের কারণে সাধারণ পদ্ধতিগুলি এমন শ্রেণির দ্বারা উত্তরাধিকারসূত্রে পাওয়া যায় যেগুলির প্রয়োজন নেই৷ এই পরিস্থিতিতে আমাদের কি করা উচিত? ঠিক আছে, আমরা স্ট্রলার ক্লাসে ফিল() পদ্ধতিটিকে ওভাররাইড করতে পারি যাতে আপনি যখন স্ট্রলারটিকে রিফিয়েল করার চেষ্টা করেন তখন কিছুই না ঘটে:

public class Stroller extends Conveyance {

   @Override
   public void fill() {
       System.out.println("A stroller cannot be refueled!");
   }
}
কিন্তু ডুপ্লিকেট কোড ব্যতীত অন্য কোন কারণে এটিকে খুব কমই একটি সফল সমাধান বলা যেতে পারে। উদাহরণস্বরূপ, বেশিরভাগ ক্লাসগুলি অভিভাবক শ্রেণীর পদ্ধতি ব্যবহার করবে, তবে বাকিরা এটিকে ওভাররাইড করতে বাধ্য হবে। যদি আমাদের 15টি ক্লাস থাকে এবং আমাদের অবশ্যই তাদের মধ্যে 5-6টির মধ্যে আচরণকে ওভাররাইড করতে হবে, কোড ডুপ্লিকেশনটি বেশ ব্যাপক হয়ে উঠবে। হয়তো ইন্টারফেস আমাদের সাহায্য করতে পারে? উদাহরণস্বরূপ, এই মত:

public interface Fillable {
  
   public void fill();
}
আমরা একটি ফিল() পদ্ধতি দিয়ে একটি পূরণযোগ্য ইন্টারফেস তৈরি করব । তারপরে, যে সমস্ত যানবাহনগুলিকে রিফুয়েল করা দরকার সেগুলি এই ইন্টারফেসটি কার্যকর করবে, যখন অন্যান্য যানবাহনগুলি (উদাহরণস্বরূপ, আমাদের বেবি স্ট্রলার) তা করবে না। কিন্তু এই বিকল্পটি আমাদের জন্য উপযুক্ত নয়। ভবিষ্যতে, আমাদের শ্রেণী শ্রেণিবিন্যাস অনেক বড় হয়ে উঠতে পারে (শুধু কল্পনা করুন পৃথিবীতে কত রকমের পরিবহন রয়েছে)। আমরা উত্তরাধিকার যুক্ত পূর্ববর্তী সংস্করণটি পরিত্যাগ করেছি, কারণ আমরা পূরণ() ওভাররাইড করতে চাই নাপদ্ধতি অনেক, অনেক বার। এখন প্রতিটি ক্লাসে তা বাস্তবায়ন করতে হবে! এবং যদি আমরা 50 আছে? এবং যদি আমাদের প্রোগ্রামে ঘন ঘন পরিবর্তন করা হয় (এবং এটি বাস্তব প্রোগ্রামগুলির জন্য প্রায় সবসময়ই সত্য!), আমাদের 50টি ক্লাসের মধ্যে দিয়ে তাড়াহুড়ো করতে হবে এবং তাদের প্রত্যেকের আচরণ ম্যানুয়ালি পরিবর্তন করতে হবে। তাহলে, শেষ পর্যন্ত, এই পরিস্থিতিতে আমাদের কী করা উচিত? আমাদের সমস্যা সমাধানের জন্য, আমরা একটি ভিন্ন উপায় বেছে নেব। যথা, আমরা আমাদের ক্লাসের আচরণকে ক্লাস থেকে আলাদা করব। ওটার মানে কি? আপনি জানেন, প্রতিটি বস্তুরই স্টেট (ডেটার একটি সেট) এবং আচরণ (পদ্ধতির একটি সেট) থাকে। আমাদের কনভেয়েন্স ক্লাসের আচরণ তিনটি পদ্ধতি নিয়ে গঠিত: go() , stop() এবং fill() । প্রথম দুটি পদ্ধতি যেমন ঠিক তেমনই। কিন্তু আমরা তৃতীয় পদ্ধতিটি বের করবকনভেয়েন্স ক্লাস। এটি ক্লাস থেকে আচরণকে আলাদা করবে (আরো সঠিকভাবে, এটি আচরণের শুধুমাত্র অংশকে আলাদা করবে, যেহেতু প্রথম দুটি পদ্ধতি তারা যেখানে থাকবে সেখানে থাকবে)। তাহলে আমাদের ফিল() পদ্ধতি কোথায় রাখা উচিত? কিছুই মনে আসে না :/ মনে হচ্ছে ঠিক যেখানে এটি হওয়া উচিত। আমরা এটিকে একটি পৃথক ইন্টারফেসে নিয়ে যাব: FillStrategy !

public interface FillStrategy {

   public void fill();
}
কেন আমরা যেমন একটি ইন্টারফেস প্রয়োজন? এটা সব সোজা. এখন আমরা বেশ কয়েকটি ক্লাস তৈরি করতে পারি যা এই ইন্টারফেসটি বাস্তবায়ন করে:

public class HybridFillStrategy implements FillStrategy {
  
   @Override
   public void fill() {
       System.out.println("Refuel with gas or electricity — your choice!");
   }
}

public class F1PitstopStrategy implements FillStrategy {
  
   @Override
   public void fill() {
       System.out.println("Refuel with gas only after all other pit stop procedures are complete!");
   }
}

public class StandardFillStrategy implements FillStrategy {
   @Override
   public void fill() {
       System.out.println("Just refuel with gas!");
   }
}
আমরা তিনটি আচরণগত কৌশল তৈরি করেছি: একটি সাধারণ গাড়ির জন্য, একটি হাইব্রিডের জন্য এবং একটি ফর্মুলা 1 রেস কারের জন্য৷ প্রতিটি কৌশল একটি ভিন্ন রিফুয়েলিং অ্যালগরিদম প্রয়োগ করে। আমাদের ক্ষেত্রে, আমরা কেবল কনসোলে একটি স্ট্রিং প্রদর্শন করি, তবে প্রতিটি পদ্ধতিতে কিছু জটিল যুক্তি থাকতে পারে। পরবর্তিতে আমরা কি করবো?

public class Conveyance {

   FillStrategy fillStrategy;

   public void fill() {
       fillStrategy.fill();
   }

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {
       System.out.println("Braking!");
   }
  
}
আমরা কনভেয়েন্স প্যারেন্ট ক্লাসে একটি ক্ষেত্র হিসাবে আমাদের FillStrategy ইন্টারফেস ব্যবহার করি। মনে রাখবেন যে আমরা একটি নির্দিষ্ট বাস্তবায়ন নির্দেশ করছি না - আমরা একটি ইন্টারফেস ব্যবহার করছি। গাড়ির ক্লাসগুলির জন্য FillStrategy ইন্টারফেসের নির্দিষ্ট বাস্তবায়নের প্রয়োজন হবে:

public class F1Car extends Conveyance {

   public F1Car() {
       this.fillStrategy = new F1PitstopStrategy();
   }
}

public class HybridCar extends Conveyance {

   public HybridCar() {
       this.fillStrategy = new HybridFillStrategy();
   }
}

public class Sedan extends Conveyance {

   public Sedan() {
       this.fillStrategy = new StandardFillStrategy();
   }
}

এর আমরা কি পেয়েছি তাকান!

public class Main {

   public static void main(String[] args) {

       Conveyance sedan = new Sedan();
       Conveyance hybrid = new HybridCar();
       Conveyance f1car = new F1Car();

       sedan.fill();
       hybrid.fill();
       f1car.fill();
   }
}
কনসোল আউটপুট:

Just refuel with gas! 
Refuel with gas or electricity — your choice! 
Refuel with gas only after all other pit stop procedures are complete!
দারুণ! রিফুয়েলিং প্রসেস যেমন কাজ করে! যাইহোক, কনস্ট্রাক্টরের প্যারামিটার হিসাবে কৌশলটি ব্যবহার করতে কিছুই আমাদের বাধা দেয় না! উদাহরণস্বরূপ, এই মত:

public class Conveyance {

   private FillStrategy fillStrategy;

   public Conveyance(FillStrategy fillStrategy) {
       this.fillStrategy = fillStrategy;
   }

   public void fill() {
       this.fillStrategy.fill();
   }

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {
       System.out.println("Braking!");
   }
}

public class Sedan extends Conveyance {

   public Sedan() {
       super(new StandardFillStrategy());
   }
}



public class HybridCar extends Conveyance {

   public HybridCar() {
       super(new HybridFillStrategy());
   }
}

public class F1Car extends Conveyance {

   public F1Car() {
       super(new F1PitstopStrategy());
   }
}
চলুন আমাদের main() পদ্ধতি চালাই (যা অপরিবর্তিত থাকে)। আমরা একই ফলাফল পেতে! কনসোল আউটপুট:

Just refuel with gas! 
Refuel with gas or electricity — your choice! 
Refuel with gas only after all other pit stop procedures are complete!
কৌশল ডিজাইন প্যাটার্ন অ্যালগরিদমগুলির একটি পরিবারকে সংজ্ঞায়িত করে, তাদের প্রতিটিকে এনক্যাপসুলেট করে এবং নিশ্চিত করে যে তারা বিনিময়যোগ্য। এটি আপনাকে ক্লায়েন্ট দ্বারা কীভাবে ব্যবহার করা হয় তা নির্বিশেষে অ্যালগরিদমগুলিকে সংশোধন করতে দেয় (এই সংজ্ঞাটি, "হেড ফার্স্ট ডিজাইন প্যাটার্নস" বই থেকে নেওয়া, আমার কাছে দুর্দান্ত বলে মনে হয়)। নকশা প্যাটার্ন: কৌশল - 4আমরা ইতিমধ্যেই বিভিন্ন বাস্তবায়ন সহ পৃথক ইন্টারফেসে (গাড়ি রিফুয়েল করার উপায়) আগ্রহী অ্যালগরিদমের পরিবারকে নির্দিষ্ট করেছি। আমরা তাদের গাড়ি থেকে আলাদা করেছি। এখন যদি আমাদের একটি নির্দিষ্ট রিফুয়েলিং অ্যালগরিদমে কোনো পরিবর্তন করতে হয়, তাহলে এটি আমাদের গাড়ির ক্লাসকে কোনোভাবেই প্রভাবিত করবে না। এবং বিনিময়যোগ্যতা অর্জনের জন্য, আমাদের কনভেয়েন্স ক্লাসে একটি একক সেটার পদ্ধতি যোগ করতে হবে :

public class Conveyance {

   FillStrategy fillStrategy;

   public void fill() {
       fillStrategy.fill();
   }

   public void go() {
       System.out.println("Moving forward");
   }

   public void stop() {
       System.out.println("Braking!");
   }

   public void setFillStrategy(FillStrategy fillStrategy) {
       this.fillStrategy = fillStrategy;
   }
}
এখন আমরা উড়ে যাওয়ার কৌশল পরিবর্তন করতে পারি:

public class Main {

   public static void main(String[] args) {

       Stroller stroller= new Stroller();
       stroller.setFillStrategy(new StandardFillStrategy());

       stroller.fill();
   }
}
যদি শিশুর স্ট্রলারগুলি হঠাৎ পেট্রোলে চলতে শুরু করে, আমাদের প্রোগ্রাম এই দৃশ্যটি পরিচালনা করার জন্য প্রস্তুত হবে :) এবং এটি সম্পর্কে! আপনি আরও একটি ডিজাইন প্যাটার্ন শিখেছেন যা বাস্তব প্রকল্পগুলিতে কাজ করার সময় নিঃসন্দেহে অপরিহার্য এবং সহায়ক হবে :) পরবর্তী সময় পর্যন্ত!
মন্তব্য
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION