개요

 프로그램은 어떤 일(문제)를 해결하는 과정이라 할 수 있는데, 이 문제를 해결하는 과정을 보통 알고리즘 이라 부르는 건 프로그래밍을 접해봤다면 이미 익숙하다. Strategy(전략) 패턴은 문제를 해결하기 위한 알고리즘 구현 부분을 교환할 수 있도록 하는 패턴이다. 알고리즘을 교체하면서 같은 문제에도 다른 방법으로 쉽게 해결하는데 목적이 있다.

 

 

역할

Strategy 역할

  전략을 선택해 사용하기 위한 인터페이스를 결정. 예제에서는 Strategy 클래스.

 

ConcreteStrategy 역할

  Strategy를 구현. 구체적인 전략(방법, 알고리즘)을 실제로 프로그래밍한다. 예제에서는 WinningStrategy, ProbStrategy 클래스.

 

Context(문맥) 역할

  Strategy를 이용하는 역할로 적절한 ConcreteStrategy 인스턴스를 Strategy에 정의된 인터페이스로 이용. 예제에서는 Player 클래스.

 

 

이득 및 유의사항

 Strategy 패턴을 사용함으로써 프로그램에 필요한 알고리즘과 다른  부분을 분리해서 구현할 수 있고, 필요에 따라 알고리즘 부분만 교체가 가능하다. 알고리즘을 개선시키거나 같은 문제에도 주어지는 조건에 따라 새로운 알고리즘을 선택할 수 있는 것이다. 

 

예제 코드

//Hand
package strategy;

public class Hand {
	public static final int HADVALUE_GUU = 0;
	public static final int HADVALUE_CHO = 1;
	public static final int HADVALUE_PAA = 2;
	public static final Hand[] hand = {
			new Hand(HADVALUE_GUU)
			,new Hand(HADVALUE_CHO)
			,new Hand(HADVALUE_PAA)
			,
	};
	
	private static final String[] name = {
		"주먹", "가위", "보",	
	};
	
	private int handvalue;
	private Hand(int handvalue) {
		this.handvalue = handvalue;
	}
	
	public static Hand getHand(int handvalue) {
		return hand[handvalue];
	}
	
	public boolean isStrongerThan(Hand h) {
		return fight(h)==1;
	}
	
	public boolean isWeakerThan(Hand h) {
		return fight(h)==-1;
	}
	
	private int fight(Hand h) {
		if(this == h) {
			return 0;
		} else if((this.handvalue+1)%3 == h.handvalue) {
			return 1;
		} else {
			return -1;
		}
	}
	
	public String toString() {
		return name[handvalue];
	}
	
}


//Strategy
package Strategy;

public interface Strategy {
	public abstract Hand nextHand();
	public abstract void study(boolean win);
}


//ConcreteStrategy1
package Strategy;

import java.util.Random;

public class WinningStrategy implements Strategy{
	private Random random;
	private boolean won = false;
	private Hand prevHand;
	
	public WinningStrategy(int seed) {
		random = new Random(seed);
	}
	
	@Override
	public Hand nextHand() {
		if(!won) {
			prevHand = Hand.getHand(random.nextInt(3));
		}
		return prevHand;
	}

	@Override
	public void study(boolean win) {
		won = win;
		
	}

}


//ConcreteStrategy2
package Strategy;

import java.util.Random;

public class ProbStrategy implements Strategy{
	private Random random;
	private int prevHandValue = 0;
	private int currentHandValue = 0;
	
	private int[][] history = {
			{1,1,1}
			,{1,1,1}
			,{1,1,1}
			,
	};
	
	public ProbStrategy(int seed) {
		random = new Random(seed);
	}
	
	@Override
	public Hand nextHand() {
		int bet = random.nextInt(getSum(currentHandValue));
		int handvalue = 0;
		if(bet<history[currentHandValue][0]) {
			handvalue = 0;
		} else if(bet < history[currentHandValue][1]) {
			handvalue = 1;
		} else {
			handvalue = 2;
		}
		
		prevHandValue = currentHandValue;
		currentHandValue = handvalue;
		return Hand.getHand(handvalue);
	}

	@Override
	public void study(boolean win) {
		if(win) {
			history[prevHandValue][currentHandValue]++;
		} else {
			history[prevHandValue][(currentHandValue+1)%3]++;
			history[prevHandValue][(currentHandValue+2)%3]++;
		}
		
	}
	
	private int getSum(int hv) {
		int sum = 0;
		for(int i=0; i<3; i++) {
			sum += history[hv][i];
		}
		return sum;
	}
	
}



//Context
package Strategy;

public class Player {
	private String name;
	private Strategy strategy;
	private int wincount;
	private int losecount;
	private int gamecount;
	public Player(String name, Strategy strategy) {
		this.name = name;
		this.strategy = strategy;
	}
	
	public Hand nextHand() {
		return strategy.nextHand();
	}
	
	public void win() {
		strategy.study(true);
		wincount++;
		gamecount++;
	}
	
	public void lose() {
		strategy.study(false);
		losecount++;
		gamecount++;
	}
	
	public void even() {
		gamecount++;
	}
	
	public String toString() {
		return "[" + name + ":" + gamecount + "games, " + wincount+"win, " + losecount + "lose" + "]";
	}
}


//Tester
package Strategy;

public class StrategyTester {
	public static void main(String[] args) {
		if(args.length != 2) {
			System.out.println("Usage : java Main randomseed1 randomseed2");
			System.out.println("Example : java Main 314 15");
			System.exit(0);
		}
		
		int seed1 = Integer.parseInt(args[0]);
		int seed2 = Integer.parseInt(args[1]);
		
		Player p1 = new Player("두리", new WinningStrategy(seed1));
		Player p2 = new Player("하나", new ProbStrategy(seed2));
		
		for(int i=0; i<10000; i++) {
			Hand nextHand1 = p1.nextHand();
			Hand nextHand2 = p2.nextHand();
			if(nextHand1.isStrongerThan(nextHand2)) {
				System.out.println("Winner: " + p1);
				p1.win();
				p2.lose();
			} else if(nextHand2.isStrongerThan(nextHand1)) {
				System.out.println("Winner: " + p2);
				p1.lose();
				p2.win();
			} else {
				System.out.println("Even..");
				p1.even();
				p2.even();
			}
		}
		System.out.println("Result: ");
		System.out.println(p1.toString());
		System.out.println(p2.toString());
	}
}

'디자인 패턴' 카테고리의 다른 글

12. Decorator 패턴  (0) 2020.12.16
11. Composite 패턴  (0) 2020.12.15
9. Bridge 패턴  (0) 2020.12.08
8. AbstractFactory 패턴  (0) 2020.12.07
7. Builder 패턴  (0) 2020.12.04

+ Recent posts