Design patterns
रणनीति पैटर्न
खोज…
रणनीति कार्यान्वयन विवरणों को छिपाना
ऑब्जेक्ट ओरिएंटेड डिज़ाइन में एक बहुत ही सामान्य दिशानिर्देश है "जितना संभव हो उतना कम लेकिन जितना आवश्यक हो"। यह रणनीति के पैटर्न पर भी लागू होता है: आमतौर पर कार्यान्वयन विवरण को छिपाने की सलाह दी जाती है, उदाहरण के लिए कौन सी कक्षाएं वास्तव में रणनीतियों को लागू करती हैं।
सरल रणनीतियों के लिए जो बाहरी मापदंडों पर निर्भर नहीं करते हैं, सबसे आम तरीका कार्यान्वयन वर्ग को निजी (नेस्टेड क्लास) या पैकेज-प्राइवेट बनाना है और एक सार्वजनिक वर्ग के स्थिर क्षेत्र के माध्यम से एक उदाहरण को उजागर करना है:
public class Animal {
private static class AgeComparator implements Comparator<Animal> {
public int compare(Animal a, Animal b) {
return a.age() - b.age();
}
}
// Note that this field has the generic type Comparator<Animal>, *not*
// Animal.AgeComparator!
public static final Comparator<Animal> AGE_COMPARATOR = new AgeComparator();
private final int age;
Animal(int age) {
this.age = age;
}
public int age() {
return age;
}
}
List<Animal> myList = new LinkedList<>();
myList.add(new Animal(10));
myList.add(new Animal(5));
myList.add(new Animal(7));
myList.add(new Animal(9));
Collections.sort(
myList,
Animal.AGE_COMPARATOR
);
सार्वजनिक क्षेत्र Animal.AGE_COMPARATOR
एक रणनीति को परिभाषित करता है जिसे बाद में Collections.sort
जैसी विधियों में उपयोग किया जा सकता है, लेकिन इसके कार्यान्वयन के बारे में उपयोगकर्ता को कुछ भी जानने की आवश्यकता नहीं है, यहां तक कि कार्यान्वयन वर्ग भी नहीं।
यदि आप चाहें, तो आप एक अनाम वर्ग का उपयोग कर सकते हैं:
public class Animal {
public static final Comparator<Animal> AGE_COMPARATOR = new Comparator<Animal> {
public int compare(Animal a, Animal b) {
return a.age() - b.age();
}
};
// other members...
}
यदि रणनीति थोड़ी अधिक जटिल है और मापदंडों की आवश्यकता होती है, तो स्टेटिक फैक्ट्री विधियों जैसे कि Collections.reverseOrder(Comparator<T>)
का उपयोग करना बहुत आम है। विधि का वापसी प्रकार किसी भी कार्यान्वयन विवरण को उजागर नहीं करना चाहिए, जैसे reverseOrder()
को लागू किया जाता है
public static <T> Comparator<T> reverseOrder(Comparator<T> cmp) {
// (Irrelevant lines left out.)
return new ReverseComparator2<>(cmp);
}
Context वर्ग के साथ जावा में रणनीति पैटर्न उदाहरण
रणनीति:
Strategy
एक व्यवहार पैटर्न है, जो संबंधित एल्गोरिदम के एक परिवार से एल्गोरिदम को गतिशील रूप से बदलने की अनुमति देता है।
विकिपीडिया से रणनीति पैटर्न का यूएमएल
import java.util.*;
/* Interface for Strategy */
interface OfferStrategy {
public String getName();
public double getDiscountPercentage();
}
/* Concrete implementation of base Strategy */
class NoDiscountStrategy implements OfferStrategy{
public String getName(){
return this.getClass().getName();
}
public double getDiscountPercentage(){
return 0;
}
}
/* Concrete implementation of base Strategy */
class QuarterDiscountStrategy implements OfferStrategy{
public String getName(){
return this.getClass().getName();
}
public double getDiscountPercentage(){
return 0.25;
}
}
/* Context is optional. But if it is present, it acts as single point of contact
for client.
Multiple uses of Context
1. It can populate data to execute an operation of strategy
2. It can take independent decision on Strategy creation.
3. In absence of Context, client should be aware of concrete strategies. Context acts a wrapper and hides internals
4. Code re-factoring will become easy
*/
class StrategyContext {
double price; // price for some item or air ticket etc.
Map<String,OfferStrategy> strategyContext = new HashMap<String,OfferStrategy>();
StrategyContext(double price){
this.price= price;
strategyContext.put(NoDiscountStrategy.class.getName(),new NoDiscountStrategy());
strategyContext.put(QuarterDiscountStrategy.class.getName(),new QuarterDiscountStrategy());
}
public void applyStrategy(OfferStrategy strategy){
/*
Currently applyStrategy has simple implementation. You can Context for populating some more information,
which is required to call a particular operation
*/
System.out.println("Price before offer :"+price);
double finalPrice = price - (price*strategy.getDiscountPercentage());
System.out.println("Price after offer:"+finalPrice);
}
public OfferStrategy getStrategy(int monthNo){
/*
In absence of this Context method, client has to import relevant concrete Strategies everywhere.
Context acts as single point of contact for the Client to get relevant Strategy
*/
if ( monthNo < 6 ) {
return strategyContext.get(NoDiscountStrategy.class.getName());
}else{
return strategyContext.get(QuarterDiscountStrategy.class.getName());
}
}
}
public class StrategyDemo{
public static void main(String args[]){
StrategyContext context = new StrategyContext(100);
System.out.println("Enter month number between 1 and 12");
int month = Integer.parseInt(args[0]);
System.out.println("Month ="+month);
OfferStrategy strategy = context.getStrategy(month);
context.applyStrategy(strategy);
}
}
उत्पादन:
Enter month number between 1 and 12
Month =1
Price before offer :100.0
Price after offer:100.0
Enter month number between 1 and 12
Month =7
Price before offer :100.0
Price after offer:75.0
समस्या कथन: जुलाई-दिसंबर के महीनों के लिए आइटम की कीमत पर 25% की छूट प्रदान करें। जनवरी-जून के महीनों के लिए कोई छूट प्रदान न करें।
उपरोक्त उदाहरण Context
साथ Strategy
पैटर्न के उपयोग को दर्शाता है। Client
लिए संपर्क के एकल बिंदु के रूप में Context
का उपयोग किया जा सकता है।
दो रणनीतियाँ - NoOfferStrategy
और QuarterDiscountStrategy
को समस्या कथन के अनुसार घोषित किया गया है।
जैसा कि आउटपुट कॉलम में दिखाया गया है, आपके द्वारा दर्ज किए गए महीने के आधार पर आपको छूट मिलेगी
रणनीति पैटर्न के लिए मामले का उपयोग करें :
इस पैटर्न का उपयोग तब करें जब आपके पास विनिमेय एल्गोरिदम का परिवार हो और आपको रन समय पर एल्गोरिदम को बदलना होगा।
सशर्त बयानों को हटाकर कोड को साफ रखें
एक संदर्भ वर्ग / जावा के बिना रणनीति पैटर्न
संदर्भ वर्ग के बिना रणनीति पैटर्न का उपयोग करने का एक सरल उदाहरण निम्नलिखित है। दो कार्यान्वयन रणनीतियाँ हैं जो इंटरफ़ेस को लागू करती हैं और एक ही समस्या को विभिन्न तरीकों से हल करती हैं। अंग्रेजीट्रांसलेशन वर्ग के उपयोगकर्ता अनुवाद विधि को कॉल कर सकते हैं और वांछित रणनीति निर्दिष्ट करके, अनुवाद के लिए किस रणनीति का उपयोग करना चाहते हैं।
// The strategy interface
public interface TranslationStrategy {
String translate(String phrase);
}
// American strategy implementation
public class AmericanTranslationStrategy implements TranslationStrategy {
@Override
public String translate(String phrase) {
return phrase + ", bro";
}
}
// Australian strategy implementation
public class AustralianTranslationStrategy implements TranslationStrategy {
@Override
public String translate(String phrase) {
return phrase + ", mate";
}
}
// The main class which exposes a translate method
public class EnglishTranslation {
// translate a phrase using a given strategy
public static String translate(String phrase, TranslationStrategy strategy) {
return strategy.translate(phrase);
}
// example usage
public static void main(String[] args) {
// translate a phrase using the AustralianTranslationStrategy class
String aussieHello = translate("Hello", new AustralianTranslationStrategy());
// Hello, mate
// translate a phrase using the AmericanTranslationStrategy class
String usaHello = translate("Hello", new AmericanTranslationStrategy());
// Hello, bro
}
}
रणनीति पैटर्न को लागू करने के लिए जावा 8 कार्यात्मक इंटरफेस का उपयोग करना
इस उदाहरण का उद्देश्य यह दिखाना है कि हम जावा 8 कार्यात्मक इंटरफेस का उपयोग करके रणनीति पैटर्न को कैसे महसूस कर सकते हैं। हम क्लासिक जावा में एक सरल उपयोग केस कोड के साथ शुरू करेंगे, और फिर इसे जावा 8 तरीके से रीकोड करेंगे।
हमारे द्वारा उपयोग की जाने वाली उदाहरण समस्या एल्गोरिदम (रणनीतियों) का एक परिवार है जो दूरी पर संवाद करने के विभिन्न तरीकों का वर्णन करता है।
क्लासिक जावा संस्करण
एल्गोरिदम के हमारे परिवार के अनुबंध को निम्नलिखित इंटरफ़ेस द्वारा परिभाषित किया गया है:
public interface CommunicateInterface {
public String communicate(String destination);
}
फिर हम कई एल्गोरिदम लागू कर सकते हैं, इस प्रकार है:
public class CommunicateViaPhone implements CommunicateInterface {
@Override
public String communicate(String destination) {
return "communicating " + destination +" via Phone..";
}
}
public class CommunicateViaEmail implements CommunicateInterface {
@Override
public String communicate(String destination) {
return "communicating " + destination + " via Email..";
}
}
public class CommunicateViaVideo implements CommunicateInterface {
@Override
public String communicate(String destination) {
return "communicating " + destination + " via Video..";
}
}
इन्हें निम्न प्रकार से त्वरित किया जा सकता है:
CommunicateViaPhone communicateViaPhone = new CommunicateViaPhone();
CommunicateViaEmail communicateViaEmail = new CommunicateViaEmail();
CommunicateViaVideo communicateViaVideo = new CommunicateViaVideo();
अगला, हम एक ऐसी सेवा लागू करते हैं जो रणनीति का उपयोग करती है:
public class CommunicationService {
private CommunicateInterface communcationMeans;
public void setCommuncationMeans(CommunicateInterface communcationMeans) {
this.communcationMeans = communcationMeans;
}
public void communicate(String destination) {
this.communcationMeans.communicate(destination);
}
}
अंत में, हम विभिन्न रणनीतियों का उपयोग इस प्रकार कर सकते हैं:
CommunicationService communicationService = new CommunicationService();
// via phone
communicationService.setCommuncationMeans(communicateViaPhone);
communicationService.communicate("1234567");
// via email
communicationService.setCommuncationMeans(communicateViaEmail);
communicationService.communicate("[email protected]");
जावा 8 कार्यात्मक इंटरफेस का उपयोग करना
अलग एल्गोरिथ्म कार्यान्वयन के अनुबंध को एक समर्पित इंटरफ़ेस की आवश्यकता नहीं है। इसके बजाय, हम मौजूदा java.util.function.Function<T, R>
का उपयोग करके वर्णन कर सकते हैं। java.util.function.Function<T, R>
इंटरफ़ेस।
एल्गोरिदम the family of algorithms
रचना the family of algorithms
विभिन्न एल्गोरिदम को लंबोदर अभिव्यक्तियों के रूप में व्यक्त किया जा सकता है। यह रणनीति वर्गों और उनके तात्कालिकता को प्रतिस्थापित करता है।
Function<String, String> communicateViaEmail =
destination -> "communicating " + destination + " via Email..";
Function<String, String> communicateViaPhone =
destination -> "communicating " + destination + " via Phone..";
Function<String, String> communicateViaVideo =
destination -> "communicating " + destination + " via Video..";
अगला, हम "सेवा" को निम्नानुसार कोड कर सकते हैं:
public class CommunicationService {
private Function<String, String> communcationMeans;
public void setCommuncationMeans(Function<String, String> communcationMeans) {
this.communcationMeans = communcationMeans;
}
public void communicate(String destination) {
this.communcationMeans.communicate(destination);
}
}
अंत में हम निम्नानुसार रणनीतियों का उपयोग करते हैं
CommunicationService communicationService = new CommunicationService();
// via phone
communicationService.setCommuncationMeans(communicateViaPhone);
communicationService.communicate("1234567");
// via email
communicationService.setCommuncationMeans(communicateViaEmail);
communicationService.communicate("[email protected]");
या और भी:
communicationService.setCommuncationMeans(
destination -> "communicating " + destination + " via Smoke signals.." );
CommunicationService.communicate("anyone");
रणनीति (PHP)
Www.phptherightway.com से उदाहरण
<?php
interface OutputInterface
{
public function load();
}
class SerializedArrayOutput implements OutputInterface
{
public function load()
{
return serialize($arrayOfData);
}
}
class JsonStringOutput implements OutputInterface
{
public function load()
{
return json_encode($arrayOfData);
}
}
class ArrayOutput implements OutputInterface
{
public function load()
{
return $arrayOfData;
}
}