전략 패턴의 실제 사례
나는 OCP 원칙 과이를 달성하기 위해 전략 패턴을 사용하는 방법에 대해 읽었습니다 .
저는 이것을 몇 사람에게 설명하려고했지만 제가 생각할 수있는 유일한 예는 "주문"이 어떤 상태인지에 따라 다른 유효성 검사 클래스를 사용하는 것입니다.
온라인에서 몇 가지 기사를 읽었지만 일반적으로 보고서 생성 / 청구서 / 유효성 검사 등과 같은 전략을 사용하는 실제 이유를 설명하지 않습니다.
전략 패턴이 일반적이라고 생각하는 실제 사례가 있습니까?
이것에 대해 :
파일을 암호화해야합니다.
작은 파일의 경우 전체 파일을 읽고 메모리에 보관하는 "메모리 내"전략을 사용할 수 있습니다 (파일 <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)
다시 말하지만, 이전 게시물이지만 여전히 검색에 표시되므로 두 가지 예제를 더 추가하겠습니다 (코드는 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 인터페이스를 구현하는 새 규칙 클래스를 만들고 필요할 때이를 전환하면됩니다.
또 다른 좋은 예 : http://www.asp.net/mvc/pluralsight에 있는 Scott Allen의 비디오 시리즈에서 응용 프로그램의 단위 테스트 부분에서 전략 패턴을 사용합니다.
그는 인기에 따라 항목을 표시하는 페이지가있는 웹 사이트를 구축합니다. 그러나 '인기'는 여러 가지 (대부분의 조회수, 대부분의 구독자, 생성 일, 대부분의 활동, 최소 댓글 수 등) 일 수 있으며, 경영진이 아직 주문 방법을 정확히 알지 못하는 경우 다른 방식으로 실험하고 싶을 수 있습니다. 나중에 주문. order 메서드를 사용하여 인터페이스 (IOrderAlgorithm 등)를 만들고 Orderer 개체가 IOrderAlgorithm 인터페이스의 구체적인 구현에 순서를 위임하도록합니다. "CommentOrderer", "ActivityOrderer"등을 만들 수 있습니다. 그리고 새 요구 사항이있을 때이를 전환하면됩니다.
몇 가지 매우 간단한 예를 생각할 수 있습니다.
- 목록 정렬. 전략은 목록의 두 항목 중 "첫 번째"항목을 결정하는 데 사용되는 비교입니다.
- 런타임에 정렬 알고리즘 자체 (QuickSort, HeapSort 등)를 선택할 수있는 애플리케이션이있을 수 있습니다.
- Log4Net 및 Log4j의 어 펜더, 레이아웃 및 필터
- UI 툴킷의 레이아웃 관리자
데이터 압축. 유일한 메서드가 다음과 같은 ICompressor 인터페이스가있을 수 있습니다.
byte [] compress (byte [] 입력);
구체적인 압축 클래스는 RunLengthCompression, DeflateCompression 등과 같은 것일 수 있습니다.
주요 사항 :
전략 은 행동 디자인 패턴입니다. 알고리즘 계열간에 전환하는 데 사용됩니다.
이 패턴에는 하나의 추상 전략 인터페이스 와 해당 인터페이스의 많은 구체적인 전략 구현 ( 알고리즘 )이 포함됩니다.
응용 프로그램은 전략 인터페이스 만 사용 합니다. 일부 구성 매개 변수에 따라 구체적인 전략 은 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의 전략 패턴
소스 메이킹 별 전략 패턴
전략 패턴의 일반적인 용도 중 하나는 사용자 정의 정렬 전략 (고차 함수가없는 언어에서)을 정의하는 것입니다. 예를 들어 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);
}
});
매일 엔터프라이즈 디렉토리에 대해 사용자 기반을 동기화하는 응용 프로그램이 있습니다. 사용자는 대학에서의 지위에 따라 자격이 있거나 자격이 없습니다. 매일 프로비저닝 프로그램이 진행되고 자격이 있어야하는 사용자가 애플리케이션에 프로비저닝되고 프로비저닝 해제되지 않은 사용자가 프로비저닝되었는지 확인합니다 (실제로는 단계적 성능 저하 알고리즘에 따라 다르지만 요점을 벗어남). 토요일에는 각 사용자의 일부 속성을 동기화하고 적절한 자격이 있는지 확인하는 더 철저한 업데이트를 수행합니다. 월말에 나는 그 달의 사용량에 따라 청구서 처리를합니다.
이 동기화를 수행하기 위해 구성 가능한 전략 패턴을 사용합니다. 메인 프로그램은 기본적으로 요일 (동기화 변경 만 / 모두 동기화)과 학사 일정에 따른 학기 시간에 따라 마스터 전략을 선택합니다. 결제주기가 종료되면 결제 전략으로 구성됩니다. 그런 다음 표준 인터페이스를 통해 선택한 전략을 실행합니다.
이것이 얼마나 흔한 지 모르겠지만 전략 패턴에 딱 맞는 것 같았습니다.
나는 이것이 오래된 질문이라는 것을 알고 있지만 최근에 구현 한 또 다른 흥미로운 예가 있다고 생각합니다.
이것은 문서 전달 시스템에서 사용되는 전략 패턴의 매우 실용적인 예입니다.
많은 문서와 일부 메타 데이터가 포함 된 아카이브를받은 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
실패하면 물건을 롤백 합니다).
제 이해에서 이것은 전략 패턴의 한 예입니다. 내가 틀렸다고 생각한다면 아래에 댓글을 달고 알려주세요. 나는 전략 패턴의 "순수한"사용을 구성하는 것이 무엇인지, 그리고 내 구현의 어떤 측면이 정의를 위반하는지 궁금합니다. 전략 인터페이스가 약간 뚱뚱하기 때문에 약간 재미있어 보인다고 생각합니다. 지금까지 본 모든 예제는 하나의 방법 만 사용하지만 여전히 이것이 알고리즘을 캡슐화한다고 생각합니다 (비즈니스 논리의 일부가 알고리즘으로 간주 될 수 있다면 그렇게 생각합니다).
전략은 전달 실행 중에 이벤트에 대한 알림도 받기 때문에 Observer 로 간주 될 수도 있지만 이는 또 다른 이야기입니다.
약간의 조사를 통해 이것은 Advisor 라고하는 "복합 패턴"(MVC, 특정 방식으로 아래에 여러 디자인 패턴을 사용하는 패턴)처럼 보입니다 . 전달을 계속할지 여부에 대한 조언자이지만 요청시 항목을 롤백 할 수 있기 때문에 활성 오류 처리기이기도합니다.
어쨌든 이것은 전략 패턴의 사용이 모두 너무 단순하거나 어리석은 느낌을 줄 수있는 매우 복잡한 예입니다. 다른 패턴과 함께 사용하면 정말 복잡하고 훨씬 더 적용 할 수 있습니다.
전략 패턴은 특히 유효성 검사 및 정렬 알고리즘에 가장 일반적으로 사용되는 패턴입니다.
간단한 실용적인 예를 들어 설명하겠습니다.
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/ 에서 동일한 예를 가져 왔습니다 .
전략 패턴의 좋은 예는 우리가 다른 캐릭터를 가질 수 있고 각 캐릭터가 공격 할 여러 무기를 가질 수 있지만 한 번에 하나의 무기 만 사용할 수있는 게임에서입니다. 그래서 우리는 캐릭터를 컨텍스트로 가지고 있습니다. 예를 들어 King, Commander, Knight, Soldier, 그리고 attack ()이 사용되는 무기에 의존하는 방법 / 알고리즘이 될 수있는 전략으로 무기를 사용합니다. 따라서 구체적인 무기 클래스가 Sword, Axe, Crossbow, BowAndArrow 등이라면 모두 attack () 메서드를 구현합니다. 더 이상의 설명이 필요하지 않다고 확신합니다.
좋은 예인 애플리케이션의 상당히 복잡한 엔진에서 전략 접근 방식을 사용했습니다. 본질적으로 엔진의 역할은 먼저 위젯을 가진 사람들의 목록을 찾는 것이었고, 두 번째 역할은 알 수없는 매개 변수 수 (가격 거리 이전 비즈니스와 같은 것)를 기반으로 위젯을 가진 최고의 사람 10 명을 파악하는 것이 었습니다. , 재고 금액, 배송 옵션 등 ...)
본질적으로 우리가 한 일은 우리가 위젯의 여러 소스를 가지고 있고 데이터를 가져와 공통 구조로 변환 할 수 있어야한다는 것을 알고 있었기 때문에 첫 번째는 데이터 검색이라는 두 가지 전략으로 문제를 나누는 것입니다.
그런 다음 일부는 매개 변수 가중치를 기반으로하는 여러 알고리즘이 있고 다른 일부는 매우 이상하고 예의 바르며 visios와 차트를 꺼내지 않고는 정의 할 수 없었습니다. 최고의 사람을 선택합니다.
우리의 서비스 자체는 본질적으로 입력, 출력을 정의하고 데이터의 일부 정규화를 수행했으며 공급자 패턴을 사용하여 전략을 사용하는 애플리케이션 특정 데이터 공급자 및 알고리즘 공급자를 플러그인했습니다. 이것은 상당히 효과적인 시스템이었습니다.
우리가 결코 해결하지 못한 전략이나 템플릿 패턴을 사용하고 있는지에 대해 몇 가지 논쟁이있었습니다.
"주문"의 상태가 상태 패턴이 아닌 것이 확실합니까? 주문 상태에 따라 다르게 처리되지 않을 것이라는 예감이 있습니다.
예를 들어 Ship on the Order 방법 을 사용하십시오.
order.Ship();
- 배송 방법이 상태에 따라 달라진다면 전략 패턴이있는 것입니다.
- 그러나 Ship () 메서드는 주문이 결제되고 주문이 아직 배송되지 않은 경우에만 성공하면 상태 패턴이있는 것입니다.
내가 찾은 상태 패턴 (및 기타 패턴)의 가장 좋은 예는 " Head First Design Patterns "라는 책에 있습니다. 놀랍습니다. 두 번째는 David Cumps의 블로깅 시리즈 패턴 입니다.
예를 들어 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.Calendar
DatetimeMath에서 세 가지 메서드를 구현하는 CalendarMath 클래스를 작성한 다음 사용합니다.
OrdinalDayOfWeekCalculator odowc2 =
new OrdinalDayOfWeekCalculator(new CalendarMath());
Calendar canadianThanksgivingCal = (Calendar)odowc2.getDate(
year, Calendar.OCTOBER, Calendar.MONDAY, 2);
몇 주 전에 도메인 객체 중 하나에 의해 구현 된 공통 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로 보내질 때 필터링하는 등의 작업을 수행했습니다.
우리는 매우 복잡한 데이터베이스가있는 엔터프라이즈 플랫폼을위한 타사 프로비저닝 인터페이스를 만들어야했습니다. 프로비저닝 할 데이터의 제출은 종속성으로 인해 올바른 순서로 데이터베이스에 기록 될 수 있도록 애플리케이션의 우선 순위 큐에 넣은 데이터 유형 목록이었습니다.
해당 데이터를 작성하는 프로세스는 매우 간단했습니다. 우선 순위 대기열의 맨 위에 계속 표시 한 다음 추출하는 객체 유형에 따라 전략을 선택했습니다.
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);
}
}
위키 백과에서
컴퓨터 프로그래밍에서 전략 패턴 (정책 패턴이라고도 함)은 런타임에 알고리즘을 선택할 수있는 행동 소프트웨어 디자인 패턴입니다. 단일 알고리즘을 직접 구현하는 대신 코드는 알고리즘 제품군에서 사용할 런타임 지침을받습니다.
Windows 그림판 응용 프로그램에서는 다른 섹션에서 모양과 색상을 독립적으로 선택할 수있는 전략 패턴을 볼 수 있습니다. 여기서 모양과 색상은 런타임에 변경할 수있는 알고리즘입니다.
'RedCircle'옵션을 제공하는 대신 빨간색으로 원을 그리려면 원하는 원과 색상을 선택할 수 있습니다.
Shape redCircle = new RedCircle(); // Without stretegy Pattern
Shaped redCircle = new Shape("red","circle"); // With Strategy pattern
전략 패턴이 없으면 모양과 색상의 데카르트 곱으로 클래스 수가 증가합니다. 또한 각 구현에 대한 인터페이스가 변경됩니다.
참고 URL : https://stackoverflow.com/questions/370258/real-world-example-of-the-strategy-pattern
'programing tip' 카테고리의 다른 글
일시적으로 auto_now / auto_now_add 비활성화 (0) | 2020.09.09 |
---|---|
불법 배포로부터 소프트웨어를 어떻게 보호합니까? (0) | 2020.09.09 |
스프링 보안 표현 언어 주석에서 사용할 사용자 지정 메서드를 만드는 방법 (0) | 2020.09.09 |
구성 파일 당 하나의 configSections 요소 만 허용되며 존재하는 경우 루트 구성 요소의 첫 번째 하위 요소 여야합니다. (0) | 2020.09.09 |
Python 함수 호출에서 stdout 출력을 캡처하는 방법은 무엇입니까? (0) | 2020.09.09 |