CodeGym /Java Blog /यादृच्छिक /रणनीती डिझाइन नमुना
John Squirrels
पातळी 41
San Francisco

रणनीती डिझाइन नमुना

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले
हाय! आजच्या धड्यात, आपण स्ट्रॅटेजी पॅटर्नबद्दल बोलू. मागील धड्यांमध्ये, आम्ही वारसा या संकल्पनेशी थोडक्यात परिचित झालो आहोत. जर तुम्ही विसरलात तर, मी तुम्हाला आठवण करून देतो की हा शब्द सामान्य प्रोग्रामिंग कार्याच्या मानक समाधानाचा संदर्भ देतो. CodeGym मध्ये, आम्ही अनेकदा म्हणतो की तुम्ही जवळजवळ कोणत्याही प्रश्नाचे उत्तर Google करू शकता. याचे कारण असे की तुमचे कार्य, ते काहीही असो, कदाचित इतर कोणीतरी यशस्वीरित्या सोडवले आहे. पॅटर्न हे सर्वात सामान्य कार्यांसाठी प्रयत्न केलेले आणि खरे उपाय आहेत किंवा समस्याग्रस्त परिस्थिती सोडवण्याच्या पद्धती आहेत. हे "चाकं" सारखे आहेत ज्यांचा तुम्हाला स्वतःहून पुन्हा शोध लावण्याची गरज नाही, परंतु तुम्हाला ते कसे आणि केव्हा वापरायचे हे माहित असणे आवश्यक आहे :) नमुन्यांचा दुसरा उद्देश एकसमान आर्किटेक्चरला प्रोत्साहन देणे आहे. दुसऱ्याचे कोड वाचणे सोपे काम नाही! प्रत्येकजण वेगवेगळे कोड लिहितो, कारण एकच काम अनेक प्रकारे सोडवता येते. पण पॅटर्नचा वापर वेगवेगळ्या प्रोग्रामरना कोडच्या प्रत्येक ओळीत न शोधता प्रोग्रामिंग लॉजिक समजण्यास मदत करतो (पहिल्यांदा पाहिल्यावरही!) आज आपण "स्ट्रॅटेजी" नावाच्या सर्वात सामान्य डिझाइन पॅटर्नपैकी एक पाहतो. डिझाइन पॅटर्न: स्ट्रॅटेजी - 2कल्पना करा की आम्ही एक प्रोग्राम लिहित आहोत जो कन्व्हेयन्स ऑब्जेक्ट्ससह सक्रियपणे कार्य करेल. आमचा कार्यक्रम नक्की काय करतो हे महत्त्वाचे नाही. आम्ही एक कन्व्हेयन्स पालक वर्ग आणि तीन चाइल्ड क्लाससह वर्ग पदानुक्रम तयार केला आहे : सेडान , ट्रक आणि 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 :/
   }
}
आमच्या प्रोग्राममध्ये आता एक कन्व्हेयन्स (बेबी स्ट्रॉलर) आहे जो सामान्य संकल्पनेत व्यवस्थित बसत नाही. त्यात पेडल्स असू शकतात किंवा रेडिओ-नियंत्रित असू शकतात, परंतु एक गोष्ट निश्चित आहे - त्यात गॅस टाकण्यासाठी जागा नसेल. आमच्‍या वर्ग पदानुक्रमामुळे त्‍याची आवश्‍यकता नसल्‍याच्‍या वर्गांच्‍या वारशाने सामान्‍य पद्धती मिळतात. या परिस्थितीत आपण काय करावे? बरं, आम्ही स्ट्रॉलर क्लासमध्ये fill() पद्धत ओव्हरराइड करू शकतो जेणेकरून तुम्ही स्ट्रॉलरमध्ये इंधन भरण्याचा प्रयत्न करता तेव्हा काहीही होणार नाही:

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();
}
आम्ही एका fill() पद्धतीने भरण्यायोग्य इंटरफेस तयार करू . त्यानंतर, ज्या कन्व्हेयन्सेसमध्ये इंधन भरण्याची गरज आहे ते हा इंटरफेस लागू करतील, तर इतर वाहतूक (उदाहरणार्थ, आमचे बेबी स्ट्रॉलर) करणार नाहीत. पण हा पर्याय आम्हाला शोभत नाही. भविष्यात, आमची वर्गाची पदानुक्रमे खूप मोठी होऊ शकतात (जगात किती वेगवेगळ्या प्रकारच्या वाहतूक आहेत याची कल्पना करा). आम्‍ही वारसा समाविष्ट असलेली मागील आवृत्ती सोडून दिली, कारण आम्‍हाला fill() ओव्‍हरराइड करायचे नाहीपद्धत अनेक, अनेक वेळा. आता प्रत्येक वर्गात त्याची अंमलबजावणी करायची आहे! आणि आमच्याकडे 50 असल्यास काय? आणि जर आमच्या प्रोग्राममध्ये वारंवार बदल केले जात असतील (आणि वास्तविक कार्यक्रमांसाठी हे जवळजवळ नेहमीच खरे असते!), तर आम्हाला सर्व 50 वर्गांमध्ये घाई करावी लागेल आणि त्या प्रत्येकाचे वर्तन व्यक्तिचलितपणे बदलावे लागेल. तर, शेवटी, या परिस्थितीत आपण काय करावे? आमच्या समस्येचे निराकरण करण्यासाठी, आम्ही एक वेगळा मार्ग निवडू. म्हणजे, आम्ही आमच्या वर्गाचे वर्तन वर्गापासून वेगळे करू. याचा अर्थ काय? तुम्हाला माहिती आहेच की, प्रत्येक वस्तूची स्थिती (डेटा संच) आणि वर्तन (पद्धतींचा संच) असतो. आमच्या कन्व्हेयन्स क्लासच्या वर्तनात तीन पद्धती आहेत: go() , stop() आणि fill() . पहिल्या दोन पद्धती जसेच्या तसे ठीक आहेत. पण आम्ही तिसरी पद्धत बाहेर काढूवाहतूक वर्ग. हे वर्तन वर्गापासून वेगळे करेल (अधिक अचूकपणे, ते वर्तनाचा फक्त एक भाग वेगळे करेल, कारण पहिल्या दोन पद्धती ते आहेत तिथेच राहतील). तर आपण आपली 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