전략 패턴의 실제 사례


95

나는 OCP 원칙 과이를 달성하기 위해 전략 패턴을 사용하는 방법에 대해 읽었습니다 .

저는 이것을 몇 사람에게 설명하려고했지만 제가 생각할 수있는 유일한 예는 "주문"이 어떤 상태인지에 따라 다른 유효성 검사 클래스를 사용하는 것입니다.

온라인에서 몇 가지 기사를 읽었지만 일반적으로 보고서 생성 / 청구서 / 유효성 검사 등과 같은 전략을 사용하는 실제 이유를 설명하지 않습니다.

전략 패턴이 일반적이라고 생각하는 실제 사례가 있습니까?

답변:


100

이것에 대해 :

파일을 암호화해야합니다.

작은 파일의 경우 전체 파일을 읽고 메모리에 보관하는 "메모리 내"전략을 사용할 수 있습니다 (파일 <1GB).

대용량 파일의 경우 파일의 일부를 메모리에서 읽고 부분적으로 암호화 된 결과를 tmp 파일에 저장하는 다른 전략을 사용할 수 있습니다.

이는 동일한 작업에 대한 두 가지 다른 전략 일 수 있습니다.

클라이언트 코드는 다음과 같습니다.

 File file = getFile();
 Cipher c = CipherFactory.getCipher( file.size() );
 c.performAction();



// implementations:
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             // load in byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             // swapt partial results to file.
         }

}

그만큼

     Cipher c = CipherFactory.getCipher( file.size() );

암호에 대한 올바른 전략 인스턴스를 반환합니다.

이게 도움이 되길 바란다.

(나는 Cipher가 올바른 단어인지조차 모르겠습니다 : P)


8
귀하의 예는 더 이상 공장 패턴이 아닙니까? 또한 예를 들어 C #에서는 작동하지 않을 것이라고 생각합니다. "getCipher ()"메소드는 정적 메소드이지만 C #에서는 인터페이스에 정적 메소드를 정의 할 수 없습니다 (Java에서도 생각하지 않지만 확실하지 않습니다).
FrenchData

10
그들은 함께 간다. 공장은 전략을 만들지 만, 전략 자체가 (기본적으로) 동일한 작업을 수행하는 알고리즘을 보유합니다. 전략은 런타임에 변경할 수도 있습니다. 당신이 맞은 공장 방법에 대해 나는 그것을 변경했습니다.
OscarRyz

공장없이 생성 할 수있는이 공장 않고, Osacars 포인트에 추가하려면 Cipher C =null; if (file.size() <= 2048) { C = new InMemoryCipherStrategy(); } else { c= SwaptToDiskCipher (); }
Abhijit Mazumder

@FrenchData에 동의합니다. 훌륭한 예가되는 동안 존재는 CipherFactory전략 패턴에 익숙하지 않은 사람들을 혼동 할 수 있습니다.
user487772

1
공장 패턴은 창조에 관한 것이고 전략은 행동에 관한 것입니다. 약간 다른 권리가 있습니까?
nhoxbypass

62

다시 말하지만, 이전 게시물이지만 여전히 검색에 표시되므로 두 가지 예제를 더 추가하겠습니다 (코드는 C #에 있음). 프로젝트 관리자가 "애플리케이션이 'X'를 수행하기를 원하지만 'X'는 아직 명확하지 않으며 가까운 장래에 변경 될 수 있습니다. " 전략 패턴을 설명하는비디오 는 스타 크래프트를 예로 사용합니다.

이 카테고리에 해당하는 항목 :

  • 정렬 :이 숫자를 정렬하고 싶지만 BrickSort, BubbleSort 또는 다른 정렬을 사용할지 알 수 없습니다.

  • 유효성 검사 : "일부 규칙"에 따라 항목을 확인해야하지만 해당 규칙이 무엇인지 아직 명확하지 않으며 새로운 규칙을 생각할 수 있습니다.

  • 게임 : 우리는 플레이어가 움직일 때 걷거나 뛰기를 원하지만 앞으로 수영, 날기, 순간 이동, 지하 굴착 등을 할 수 있어야합니다.

  • 정보 저장 : 애플리케이션이 정보를 데이터베이스에 저장하기를 원하지만 나중에 파일을 저장하거나 웹 호출을 할 수 있어야합니다.

  • 출력 : X를 일반 문자열로 출력해야하지만 나중에 CSV, XML, JSON 등이 될 수 있습니다.


사용자가 데이터베이스의 사람들에게 제품을 할당 할 수있는 프로젝트가 있습니다. 개인에 대한이 제품 지정은 일부 비즈니스 규칙에 따라 "승인 됨"또는 "거부 됨"상태입니다. 예 : 사용자가 특정 연령의 사람에게 제품을 할당하면 해당 상태는 거부되어야합니다. 항목에서 두 필드의 차이가 50보다 크면 상태가 거부됩니다.

이제 개발 단계에서 이러한 비즈니스 규칙은 아직 완전히 명확하지 않으며 언제든지 새로운 규칙이 나올 수 있습니다. stragety-pattern의 힘은 IRule 목록이 제공되는 RuleAgent를 만든 것입니다.

public interface IRule {
    bool IsApproved(Assignment assignment); 
 }

사람에게 제품을 할당하는 순간 RuleAgent를 만들고 규칙 목록 (모두 IRule을 구현 함)을 제공하고 할당을 확인하도록 요청합니다. 그것은 모든 규칙을 통과 할 것입니다. 그들은 모두 동일한 인터페이스를 구현하기 때문에 모두 IsApproved메소드를 가지고 있으며 그중 하나가 false를 반환하면 false를 반환합니다.

예를 들어 관리자가 갑자기 나타나서 말하면 인턴에 대한 모든 할당 또는 초과 근무에 대한 모든 할당을 거부해야합니다. 다음과 같이 새 수업을 만듭니다.

public OvertimeRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Timesheet >= 40)
        {
            return false;
        }
        return true;
    }
}

public InternRule : IRule
{
    public bool IsApproved(Assignment assignment) //Interface method
    {
        if (assignment.Person.Title == "Intern")
        {
            return false;
        }
        return true;
    }
}

if 문이나 코드를 계속 추가하거나 제거 할 필요가 없다는 것을 알 수 있습니다. IRUle 인터페이스를 구현하는 새 규칙 클래스를 만들고 필요할 때이를 전환하면됩니다.


또 다른 좋은 예 : Scott Allen의 비디오 시리즈 ( http://www.asp.net/mvc/pluralsight) 에서 애플리케이션의 단위 테스트 부분에서 전략 패턴을 사용합니다.

그는 인기에 따라 항목을 표시하는 페이지가있는 웹 사이트를 구축합니다. 그러나 '인기'는 여러 가지 (대부분의 조회수, 대부분의 구독자, 생성 일, 대부분의 활동, 최소 댓글 수 등) 일 수 있으며, 경영진이 아직 주문 방법을 정확히 알지 못하는 경우 다른 방식으로 실험하고 싶을 수 있습니다. 나중에 주문. order 메서드를 사용하여 인터페이스 (IOrderAlgorithm 등)를 만들고 Orderer 개체가 IOrderAlgorithm 인터페이스의 구체적인 구현에 순서를 위임하도록합니다. "CommentOrderer", "ActivityOrderer"등을 만들 수 있습니다. 그리고 새 요구 사항이 발생하면이를 전환하면됩니다.


나는 이것이 질문의 범위를 벗어난 것을 알고 있지만 다음에 무엇이 올까요? 우리는 InternRule지금 이것을 가지고 있지만 어떻게 트리거 OvertimeRule합니까? OvertimeRule.IsApproved지금 호출 된 논리가 호출되도록하려면 어떻게해야 InternRule.IsApproved합니까?
Spencer Ruport

14

주요 사항 :

  1. 전략 은 행동 디자인 패턴입니다. 알고리즘 계열간에 전환하는 데 사용됩니다.

  2. 이 패턴에는 하나의 추상 전략 인터페이스 와 해당 인터페이스의 많은 구체적인 전략 구현 ( 알고리즘 )이 포함됩니다.

  3. 응용 프로그램은 전략 인터페이스 만 사용 합니다. 일부 구성 매개 변수에 따라 구체적인 전략interface에 태그가 지정됩니다 .

Wikipedia의 UML 다이어그램

여기에 이미지 설명 입력

실제 단어 예 : 항공사에서 몇 달 (7 월 -12 월) 동안 할인을 제공 합니다. 월 수에 따라 가격 옵션을 결정하는 하나의 요금 모듈을 가질 수 있습니다 .

간단한 예를 살펴보십시오. 이 예는 온라인 소매 응용 프로그램으로 확장 할 수 있으며, 특별한 날 / 행복한 시간에 장바구니 항목에 쉽게 할인을 제공합니다.

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 use 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

유용한 기사 :

dzone의 전략 패턴

소스 메이킹 별 전략 패턴


고마워요 .... 완벽하게 이해합니다 .... 동의했습니다. applyStrategy ()는 많은 흑 마법을 성취하는 괴물입니다. 또한 전략
컨텍스트

12

몇 가지 매우 간단한 예를 생각할 수 있습니다.

  • 목록 정렬. 전략은 목록의 두 항목 중 "첫 번째"항목을 결정하는 데 사용되는 비교입니다.
  • 런타임에 정렬 알고리즘 자체 (QuickSort, HeapSort 등)를 선택할 수있는 애플리케이션이있을 수 있습니다.
  • Log4NetLog4j의 어 펜더, 레이아웃 및 필터
  • UI 툴킷의 레이아웃 관리자
  • 데이터 압축. 유일한 메서드가 다음과 같은 ICompressor 인터페이스가있을 수 있습니다.

    byte [] compress (byte [] 입력);

    구체적인 압축 클래스는 RunLengthCompression, DeflateCompression 등과 같은 것일 수 있습니다.


9

전략 패턴의 일반적인 용도 중 하나는 사용자 정의 정렬 전략 (고차 함수가없는 언어에서)을 정의하는 것입니다. 예를 들어 Java에서 문자열 목록을 길이별로 정렬하고 익명의 내부 클래스 (전략 인터페이스 구현)를 전달합니다.

List<String> names = Arrays.asList("Anne", "Joe", "Harry");
Collections.sort(names, new Comparator<String>() {
  public int compare(String o1, String o2) {
    return o1.length() - o2.length();
  }
});
Assert.assertEquals(Arrays.asList("Joe", "Anne", "Harry"), names);

비슷한 방식으로, 전략은 예를 들어 db4o에서 객체 데이터베이스가있는 네이티브 쿼리에 사용할 수 있습니다.

List<Document> set = db.query(new Predicate<Document>() {
  public boolean match(Document candidate) {
    return candidate.getSource().contains(source);
  }
});

8

매일 엔터프라이즈 디렉토리에 대해 사용자 기반을 동기화하는 응용 프로그램이 있습니다. 사용자는 대학에서의 지위에 따라 자격이 있거나 자격이 없습니다. 매일 프로비저닝 프로그램이 진행되고 자격을 갖추어야하는 사용자가 애플리케이션에 프로비저닝되고 프로비저닝 해제되지 않은 사용자가 프로비저닝되었는지 확인합니다 (실제로는 단계적 성능 저하 알고리즘에 따라 다르지만 요점을 벗어남). 토요일에는 각 사용자의 일부 속성을 동기화하고 적절한 자격이 있는지 확인하는 더 철저한 업데이트를 수행합니다. 월말에 나는 그 달의 사용량에 따라 청구서 처리를합니다.

이 동기화를 수행하기 위해 구성 가능한 전략 패턴을 사용합니다. 메인 프로그램은 기본적으로 요일 (동기화 변경 만 / 모두 동기화)과 학사 일정에 따른 학기 시간에 따라 마스터 전략을 선택합니다. 결제주기가 종료되면 결제 전략으로 구성됩니다. 그런 다음 표준 인터페이스를 통해 선택한 전략을 실행합니다.

이것이 얼마나 흔한 지 모르겠지만 전략 패턴에 딱 맞는 것 같았습니다.


이것은 아주 좋은 예입니다. 또한 명령과 전략 패턴의 차이점을 한마디로 명확하게 알려줍니다. "기본 프로그램은 기본적으로 요일에 따라 마스터 전략을 선택 합니다."
Utsav T

7

나는 이것이 오래된 질문이라는 것을 알고 있지만 최근에 구현 한 또 다른 흥미로운 예가 있다고 생각합니다.

이것은 문서 전달 시스템에서 사용되는 전략 패턴의 매우 실용적인 예입니다.

많은 문서와 일부 메타 데이터가 포함 된 아카이브를받은 PDF 전달 시스템이 있습니다. 메타 데이터를 기반으로 문서를 넣을 위치를 결정했습니다. 말하자면, 데이터에 따라, 나는에서 문서를 저장할 수 A, B또는 C스토리지 시스템 또는 세 가지의 혼합을.

여러 고객이이 시스템을 사용했으며 오류 발생시 롤백 / 오류 처리 요구 사항이 달랐습니다. 하나는 배달 시스템이 첫 번째 오류에서 중지하고 모든 문서가 이미 저장소에 배달 된 상태로 두지 만 프로세스를 중지하고 다른 것은 배달하지 않기를 원했습니다. ; 다른 하나는에 B저장할 때 오류가 발생한 경우 롤백하기를 원했지만 C이미 전달 된 것은 그대로 두었습니다 A. 세 번째 또는 네 번째 것도 다른 요구 사항을 가질 것이라고 상상하기 쉽습니다.

문제를 해결하기 위해 전달 논리와 모든 저장소에서 항목을 롤백하는 방법이 포함 된 기본 전달 클래스를 만들었습니다. 이러한 메서드는 오류 발생시 전달 시스템에서 실제로 호출되지 않습니다. 대신 클래스는 종속성 주입을 사용하여 "롤백 / 오류 처리 전략"클래스 (시스템을 사용하는 고객 기반)를 수신합니다.이 클래스는 오류 발생시 호출되고 해당 전략에 적합한 경우 롤백 메서드를 호출합니다.

전달 클래스 자체는 전략 클래스에 무슨 일이 일어나고 있는지 (어떤 문서가 어떤 스토리지에 전달되었으며 어떤 오류가 발생했는지)보고하고 오류가 발생할 때마다 전략에 계속할지 여부를 묻습니다. 전략에 "중지"라고 표시되면 클래스는 이전에보고 된 정보를 사용하여 전달 클래스에서 호출 할 롤백 메서드를 결정하거나 아무 작업도하지 않는 전략의 "정리"메서드를 호출합니다.

rollbackStrategy.reportSuccessA(...);
rollbackStrategy.reportFailureB(...);

if (rollbackStrategy.mustAbort()) {
    rollbackStrategy.rollback(); // rollback whatever is needed based on reports
    return false;
}

지금은 두 개의 서로 다른 전략을 가지고 그래서 하나는이다 QuitterStrategy다른 하나 (첫 번째 오류 아무것도 정리에 종료하는이)입니다 MaximizeDeliveryToAStrategy하지 프로세스 중단하고 가능한 한 많이 시도하는 (결코 저장에 전달 롤백 물건 A,하지만 B배달이 C실패하면 물건을 롤백 합니다).

제 이해에서 이것은 전략 패턴의 한 예입니다. 내가 틀렸다고 생각한다면 아래에 댓글을 달고 알려주세요. 전략 패턴의 "순수한"사용을 구성하는 것이 무엇인지, 그리고 내 구현의 어떤 측면이 정의를 위반하는지 궁금합니다. 전략 인터페이스가 약간 뚱뚱하기 때문에 약간 재미있어 보인다고 생각합니다. 지금까지 본 모든 예제는 하나의 방법 만 사용하지만 여전히 알고리즘을 캡슐화한다고 생각합니다 (비즈니스 로직의 일부가 알고리즘으로 간주 될 수 있다면 그렇게 생각합니다).

전략은 전달 실행 중에 이벤트에 대한 알림도 받기 때문에 옵저버 로 간주 될 수도 있습니다. 있지만 이는 또 다른 이야기입니다.

약간의 조사를 통해 이것은 Advisor 라는 "복합 패턴"(예 : MVC, 특정 방식으로 아래에 여러 디자인 패턴을 사용하는 패턴)처럼 보입니다 . 전달을 계속할지 여부에 대한 조언자이지만 요청시 항목을 롤백 할 수 있기 때문에 활성 오류 처리기이기도합니다.

어쨌든 이것은 전략 패턴의 사용이 모두 너무 단순하거나 어리석은 느낌을 줄 수있는 매우 복잡한 예입니다. 다른 패턴과 함께 사용하면 정말 복잡하고 훨씬 더 적용 할 수 있습니다.


6

전략 패턴은 특히 유효성 검사 및 정렬 알고리즘에 가장 일반적으로 사용되는 패턴입니다.

간단한 실용적인 예를 들어 설명하겠습니다.

enum Speed {
  SLOW, MEDIUM, FAST;
}

class Sorter {
 public void sort(int[] input, Speed speed) {
    SortStrategy strategy = null;
    switch (speed) {
    case SLOW:
        strategy = new SlowBubbleSortStrategy();
        break;
    case MEDIUM:
        strategy = new MediumInsertationSortStrategy();
        break;

    case FAST:
        strategy = new FastQuickSortStrategy();
        break;
    default:
        strategy = new MediumInsertationSortStrategy();
    }
    strategy.sort(input);
 }

}

interface SortStrategy {

    public void sort(int[] input);
}

class SlowBubbleSortStrategy implements SortStrategy {

   public void sort(int[] input) {
    for (int i = 0; i < input.length; i++) {
        for (int j = i + 1; j < input.length; j++) {
            if (input[i] > input[j]) {
                int tmp = input[i];
                input[i] = input[j];
                input[j] = tmp;
            }
        }
    }
    System.out.println("Slow sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
  }

 }

class MediumInsertationSortStrategy implements SortStrategy {

public void sort(int[] input) {
    for (int i = 0; i < input.length - 1; i++) {
        int k = i + 1;
        int nxtVal = input[k];
        while (input[k - 1] > nxtVal) {
            input[k] = input[k - 1];
            k--;
            if (k == 0)
                break;
        }
        input[k] = nxtVal;
    }
    System.out.println("Medium sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }

 }

}

class FastQuickSortStrategy implements SortStrategy {

public void sort(int[] input) {
    sort(input, 0, input.length-1);
    System.out.println("Fast sorting is done and the result is :");
    for (int i : input) {
        System.out.print(i + ",");
    }
}

private void sort(int[] input, int startIndx, int endIndx) {
    int endIndexOrig = endIndx;
    int startIndexOrig = startIndx;
    if( startIndx >= endIndx)
        return;
    int pavitVal = input[endIndx];
    while (startIndx <= endIndx) {
        while (input[startIndx] < pavitVal)
            startIndx++;
        while (input[endIndx] > pavitVal)
            endIndx--;
        if( startIndx <= endIndx){
            int tmp = input[startIndx];
            input[startIndx] = input[endIndx];
            input[endIndx] = tmp;
            startIndx++;
            endIndx--;
        }
    }
    sort(input, startIndexOrig, endIndx);
    sort(input, startIndx, endIndexOrig);
 }

}  

이에 대한 테스트 코드는

public class StrategyPattern {
  public static void main(String[] args) {
    Sorter sorter = new Sorter();
    int[] input = new int[] {7,1,23,22,22,11,0,21,1,2,334,45,6,11,2};
    System.out.print("Input is : ");
    for (int i : input) {
        System.out.print(i + ",");
    }
    System.out.println();
    sorter.sort(input, Speed.SLOW);
 }

}

http://coder2design.com/strategy-pattern/ 에서 동일한 예를 가져 왔습니다 .


전략 패턴의 다양한 용도 : 유효성 검사 : 코드에서 많은 유효성 검사를 수행해야하는 경우. 다른 알고리즘 : 특히 버블 정렬 또는 빠른 정렬과 같은 다른 정렬 알고리즘을 사용할 수있는 경우. 정보 저장 : 데이터베이스 또는 파일 시스템과 같은 다른 장소에서 정보를 수집 할 수있는 경우. 파싱 ​​: 파싱하는 동안 다른 입력에 대해 다른 전략을 사용할 수 있습니다. 필터링 전략. 레이아웃 전략.
Jatinder Pal 2015

5

전략 패턴의 좋은 예는 우리가 다른 캐릭터를 가질 수 있고 각 캐릭터가 공격 할 여러 무기를 가질 수 있지만 한 번에 하나의 무기 만 사용할 수있는 게임에서입니다. 그래서 우리는 캐릭터를 컨텍스트로 가지고 있습니다. 예를 들어 King, Commander, Knight, Soldier, 그리고 attack ()이 사용되는 무기에 의존하는 방법 / 알고리즘이 될 수있는 전략으로 무기를 사용합니다. 따라서 구체적인 무기 클래스가 Sword, Axe, Crossbow, BowAndArrow 등이라면 모두 attack () 메서드를 구현합니다. 더 이상의 설명이 필요하지 않다고 확신합니다.


1
나는 받아 들여진 대답이이 예에 대해 이야기해야한다고 생각했다. :)
Jeancarlo Fontalvo

2

좋은 예인 애플리케이션의 상당히 복잡한 엔진에서 전략 접근 방식을 사용했습니다. 본질적으로 엔진의 역할은 먼저 위젯을 보유한 사람들의 목록을 찾는 것이었고, 두 번째 역할은 알 수없는 매개 변수 수 (가격 거리 이전 비즈니스와 같은 것)를 기반으로 위젯을 가진 최고의 10 명의 사람들을 파악하는 것이 었습니다. , 재고 금액, 배송 옵션 등 ...)

본질적으로 우리가 한 일은 우리가 위젯의 여러 소스를 가지고 있고 데이터를 가져와 공통 구조로 변환 할 수 있어야한다는 것을 알고 있었기 때문에 첫 번째는 데이터 검색이라는 두 가지 전략으로 문제를 나누는 것입니다.

그런 다음 일부는 매개 변수 가중치를 기반으로하는 여러 알고리즘이 있고 다른 일부는 매우 이상하고 예의 바르며 visios와 차트를 꺼내지 않고는 정의 할 수 없었으며 그림을 얻을 수 있다는 사실도 깨달았습니다. 최고의 사람을 선택합니다.

우리의 서비스 자체는 본질적으로 입력, 출력을 정의하고 데이터의 일부 정규화를 수행했으며 공급자 패턴을 사용하여 전략을 사용하는 애플리케이션 특정 데이터 공급자 및 알고리즘 공급자를 플러그인했습니다. 이것은 상당히 효과적인 시스템이었습니다.

우리가 결코 해결하지 못한 전략이나 템플릿 패턴을 사용하고 있는지에 대해 몇 가지 논쟁이있었습니다.


2

"주문"의 상태가 상태 패턴이 아닌 것이 확실합니까? 주문 상태에 따라 다르게 처리되지 않을 것이라는 예감이 있습니다.

예를 들어 Ship on the Order 방법 을 사용하십시오.

order.Ship();
  • 배송 방법이 상태 기능에 따라 다르면 전략 패턴이있는 것입니다.
  • 그러나 Ship () 메서드는 주문이 지불되고 주문이 아직 배송되지 않은 경우에만 성공하면 상태 패턴이있는 것입니다.

내가 찾은 상태 패턴 (및 기타 패턴)의 가장 좋은 예는 " Head First Design Patterns "라는 책에 있습니다. 놀랍습니다. 두 번째는 David Cumps의 블로깅 시리즈 패턴 입니다.


2

예를 들어 2014 년 10 월 두 번째 월요일과 같이 주어진 월과 연도 의 n 번째 Xday 를 계산하는 알고리즘을 작성한다고 가정 해 보겠습니다 . Android의 Time 클래스 android.text.format.Time를 사용 하여 날짜를 나타내려고하지만 일반 알고리즘도 작성하려고합니다. 에도 적용될 수 있습니다 java.util.Calendar.

이것이 내가 한 일입니다.

DatetimeMath.java에서 :

public interface DatetimeMath { 
    public Object createDatetime(int year, int month, int day);

    public int getDayOfWeek(Object datetime);

    public void increment(Object datetime);
}

TimeMath.java에서 :

public class TimeMath implements DatetimeMath {
    @Override
    public Object createDatetime(int year, int month, int day) {
        Time t = new Time();
        t.set(day, month, year);
        t.normalize(false);
        return t;
    }

    @Override
    public int getDayOfWeek(Object o) {
        Time t = (Time)o;
        return t.weekDay;
    }   

    @Override
    public void increment(Object o) {
        Time t = (Time)o;
        t.set(t.monthDay + 1, t.month, t.year);
        t.normalize(false);
    }
}

OrdinalDayOfWeekCalculator.java에서 일반 알고리즘이있는 클래스 :

public class OrdinalDayOfWeekCalculator {   
    private DatetimeMath datetimeMath;

    public OrdinalDayOfWeekCalculator(DatetimeMath m) {
        datetimeMath = m;
    }

    public Object getDate(int year, int month, int dayOfWeek, int ordinal) {
        Object datetime = datetimeMath.createDatetime(year, month, 1);
        if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
            return datetime;
        } 
        int xDayCount = 0;
        while (xDayCount != ordinal) {
            datetimeMath.increment(datetime);
            if (datetimeMath.getDayOfWeek(datetime) == dayOfWeek) {
                xDayCount++;
            }
        }
        return datetime;
    }
}

내 Android 앱에서 다음과 같이 호출합니다.

OrdinalDayOfWeekCalculator odowc = 
        new OrdinalDayOfWeekCalculator(new TimeMath());
Time canadianThanksgiving = (Time)odowc.getDate(
        year, Calendar.OCTOBER, Time.MONDAY, 2);

에 대해 동일한 알고리즘을 재사용하려면 java.util.CalendarDatetimeMath에서 세 가지 메서드를 구현하는 CalendarMath 클래스를 작성한 다음

OrdinalDayOfWeekCalculator odowc2 = 
        new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
        year, Calendar.OCTOBER, Calendar.MONDAY, 2);

2
public class StrategyDemo {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        Item item1 = new Item("1234", 10);
        Item item2 = new Item("5678", 40);

        cart.addItem(item1);
        cart.addItem(item2);

        // pay by paypal
        cart.pay(new PaypalStrategy("myemail@example.com", "mypwd"));

        // pay by credit card
        cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
    }
}

interface PaymentStrategy {
    public void pay(int amount);
}

class CreditCardStrategy implements PaymentStrategy {

    private String name;
    private String cardNumber;
    private String cvv;
    private String dateOfExpiry;

    public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate) {
        this.name = nm;
        this.cardNumber = ccNum;
        this.cvv = cvv;
        this.dateOfExpiry = expiryDate;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid with credit/debit card");
    }

}

class PaypalStrategy implements PaymentStrategy {

    private String emailId;
    private String password;

    public PaypalStrategy(String email, String pwd) {
        this.emailId = email;
        this.password = pwd;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + " paid using Paypal.");
    }

}

class Item {

    private String upcCode;
    private int price;

    public Item(String upc, int cost) {
        this.upcCode = upc;
        this.price = cost;
    }

    public String getUpcCode() {
        return upcCode;
    }

    public int getPrice() {
        return price;
    }

}

class ShoppingCart {

    // List of items
    List<Item> items;

    public ShoppingCart() {
        this.items = new ArrayList<Item>();
    }

    public void addItem(Item item) {
        this.items.add(item);
    }

    public void removeItem(Item item) {
        this.items.remove(item);
    }

    public int calculateTotal() {
        int sum = 0;
        for (Item item : items) {
            sum += item.getPrice();
        }
        return sum;
    }

    public void pay(PaymentStrategy paymentMethod) {
        int amount = calculateTotal();
        paymentMethod.pay(amount);
    }
}

1

몇 주 전에 도메인 객체 중 하나에 의해 구현 된 공통 Java 인터페이스를 추가했습니다. 이 도메인 개체는 데이터베이스에서로드되었으며 데이터베이스 표현은 약 10 개 이상의 분기가있는 스타 스키마였습니다. 이러한 무거운 도메인 개체를 갖는 결과 중 하나는 무게는 덜하지만 동일한 스키마를 나타내는 다른 도메인 개체를 만들어야한다는 것입니다. 그래서 다른 경량 객체도 동일한 인터페이스를 구현하도록했습니다. 그렇지 않으면 우리가 가지고 있었다 :

public interface CollectibleElephant { 
    long getId();
    String getName();
    long getTagId();
}

public class Elephant implements CollectibleElephant { ... }
public class BabyElephant implements CollectibleElephant { ... }

원래는 s CollectibleElephant를 정렬하는 데 사용 하고 싶었습니다 Elephant. 꽤 빨리, 팀원 CollectibleElephant들이 보안 검사를 실행하고 GUI로 보내질 때 필터링하는 등의 작업을 수행했습니다.


1

우리는 매우 복잡한 데이터베이스가있는 엔터프라이즈 플랫폼을위한 타사 프로비저닝 인터페이스를 만들어야했습니다. 프로비저닝 할 데이터의 제출은 종속성으로 인해 올바른 순서로 데이터베이스에 기록 될 수 있도록 애플리케이션의 우선 순위 큐에 넣은 데이터 유형 목록이었습니다.

해당 데이터를 작성하는 프로세스는 매우 간단했습니다. 우선 순위 대기열의 맨 위에 계속 표시 한 다음 추출하는 객체 유형에 따라 전략을 선택했습니다.


0

위키 백과에서

컴퓨터 프로그래밍에서 전략 패턴 (정책 패턴이라고도 함)은 런타임에 알고리즘을 선택할 수있는 행동 소프트웨어 디자인 패턴입니다. 단일 알고리즘을 직접 구현하는 대신 코드는 알고리즘 제품군에서 사용할 런타임 지침을받습니다.

Windows 그림판 응용 프로그램에서는 다른 섹션에서 모양과 색상을 독립적으로 선택할 수있는 전략 패턴을 볼 수 있습니다. 여기에서 모양과 색상은 런타임에 변경할 수있는 알고리즘입니다.

'RedCircle'옵션을 제공하는 대신 빨간색으로 원을 그리려면 원하는 원과 색상을 선택할 수 있습니다.

Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern

전략 패턴이 없으면 모양과 색상의 데카르트 곱으로 클래스 수가 증가합니다. 또한 각 구현에 대한 인터페이스가 변경됩니다.


0

예를 들어 AI 적들이있는 슈팅 게임을 상상해보십시오. 당신은 그들이 무슨 일이 일어나는지에 따라 다른 방식으로 계속 싸우기를 원합니다. .. 전략 패턴을 사용하면 특정 또는 행동이 수행되는 방식을 지속적으로 반복하고 동적으로 변경할 수 있습니다.

interface FightingStategy{
    public void fight();
}
public Defense implements FightingStrategy{
    public void figth(){
        ... hide behind wall to shoot
    }
}
public Berserker implements FightingStrategy{
    public void fight(){
        ... run towards you, headrolls and shoots
    }
}
public Dead implements FightingStrategy{
    public void fight(){
        ... is dead, doesn't move
    }
}

public AiShooter{

    FightingStrategy fightingStrategy;

    public AiShooter(){
        fightStrategy = new Berserker();
    }

    public void fight(){
        this.fightingStrategy.fight();
    }

    public void changeStrategy(FightingStrategy f){
        this.fightingStrategy = f;
    }
}

public static void main(){

    ... create list of AiShooters...
    while (condition){
        list.forEach(shooter -> shooter.fight());
    }
    ... you shoot back
    list.ForEach(shooter -> shooter.changeStrategy(new 
Defense()));

    ... you kill one
    list.get(n).changeStrategy(new Dead());
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.