수색…


숨기기 전략 구현 세부 정보

객체 지향 설계의 가장 일반적인 지침은 "가능한 한 적지 만 필요한만큼"입니다. 이는 전략 패턴에도 적용됩니다. 구현 세부 정보 (예 : 전략을 실제로 구현하는 클래스)를 숨기는 것이 좋습니다.

외부 매개 변수에 의존하지 않는 간단한 전략의 경우 가장 일반적인 방법은 구현 클래스 자체를 private (중첩 된 클래스) 또는 package-private로 설정하고 공용 클래스의 정적 필드를 통해 인스턴스를 노출하는 것입니다.

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_COMPARATORCollections.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 클래스를 사용한 java의 전략 패턴 예제

계략:

Strategy 은 행동 패턴이며 알고리즘을 관련 알고리즘 계열에서 동적으로 변경할 수 있습니다.

위키피디아의 전략 패턴의 UML

여기에 이미지 설명을 입력하십시오. :

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

문제 성명서 : 7 월 -12 월에 품목 가격을 25 % 할인합니다. 1 월 -6 월에 할인을 제공하지 마십시오.

위의 예는 Context 가있는 Strategy 패턴의 사용법을 보여줍니다. ContextClient 의 단일 연결 지점으로 사용할 수 있습니다.

두 가지 전략 - NoOfferStrategyQuarterDiscountStrategy 는 문제 설명문에 따라 선언되었습니다.

출력란에 표시된대로 입력 한 달에 따라 할인을 받게됩니다.

전략 패턴에 대한 유스 케이스 :

  1. 교환 가능한 알고리즘 계열을 가지고 있고 런타임에 알고리즘을 변경해야하는 경우이 패턴을 사용하십시오.

  2. 조건문을 제거하여 코드를보다 깨끗하게 유지하십시오.

컨텍스트 클래스가없는 전략 패턴 / Java

다음은 컨텍스트 클래스없이 전략 패턴을 사용하는 간단한 예입니다. 인터페이스를 구현하고 동일한 문제를 다른 방식으로 해결하는 두 가지 구현 전략이 있습니다. EnglishTranslation 클래스의 사용자는 translate 메소드를 호출하고 원하는 전략을 지정하여 변환에 사용할 전략을 선택할 수 있습니다.

// 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
    }
}

Java 8 기능 인터페이스를 사용하여 전략 패턴 구현

이 예제의 목적은 Java 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]");

Java 8 기능 인터페이스 사용

다른 알고리즘 구현의 계약에는 전용 인터페이스가 필요하지 않습니다. 대신, 기존 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;
    }
}


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow