Java로 배우는 디자인패턴 입문 Chapter 10. Strategy 알고리즘을 모두 교체하다 2004-1
전략 Strategy 패턴 01. Strategy 적과 싸울 때의 책략 군대를 움직일 때의 작전 문제를 해결해 나갈 때의 바업 프로그래밍에서는 ‘알고리즘’ Strategy 패턴 알고리즘을 구현한 부분이 모두 교환 가능하도록 함 알고리즘(전략, 작전, 책략)을 교체해서 동일한 문제를 다른 방법으로 해결하는 패턴 10. Strategy /42
컴퓨터로 ‘가위바위보’ 하는 게임 두 가지 전략 02. 예제 프로그램 WinningStrategy ProbStrategy 전략: 이기면 다음 번에도 같은 손을 내민다. ProbStrategy 전략: 바로 전에 내밀었던 손에서 다음에 내밀 손을 확률적으로 계산한다. 10. Strategy /42
02. 예제 프로그램 클래스와 인터페이스 10. Strategy /42
02. 예제 프로그램 클래스 다이어그램 위임 10. Strategy /42
Hand 클래스 02. 예제 프로그램 가위바위보의 손을 나타내는 클래스 handvalue 필드: 주먹은 0, 가위는 1, 보는 2로 표현 getHand( ) 가위바위보를 나타내는 숫자로부터 해당 손을 반환함 isStrongerThan( ) 현재 손이 입력 인자로 들어온 손을 이기면 true를 반환함 isWeakerThan( ) 현재 손이 입력 인자로 들어온 손에게 지면 true를 반환함 10. Strategy /42
Hand 클래스 02. 예제 프로그램 fight( ) toString( ): 현재 손해 해당하는 문자열을 반환한다. 현재 손이 입력인자 손과 무승부면 0, 이기면 1, 지면 -1을 반환함 우열 판정하는 수식 현재 손이 주먹(0)이고 입력 손이 가위(1)라면 또는, 현재 손이 가위(1)이고 입력 손이 보(2)라면 또는, 현재 손이 보(2)이고, 입력 손이 주먹(0)이라면 현재 손이 이긴다. => 1을 반환한다. 코드에서 this를 생략해도 된다. toString( ): 현재 손해 해당하는 문자열을 반환한다. (this.handvalue + 1) % 3 == h.handvalue (handvalue + 1) % 3 == h.handvalue 10. Strategy /42
Strategy 인터페이스 02. 예제 프로그램 가위바위보의 ‘전략’을 위한 추상 메소드를 모아놓은 곳 nextHand( ) 다음에 내밀 손을 얻기 위해 호출하는 메소드 이 메소드가 호출되면, Strategy 인터페이스를 구현한 클래스가 지혜를 모아 ‘다음 손’을 결정함 study( ) 전략을 위한 준비를 하는 메소드 이긴 경우에는 Player가 study(true)를 호출하고, 진 경우에는 Player가 study(false)를 호출한다. 10. Strategy /42
WinningStrategy 클래스 02. 예제 프로그램 Strategy 인터페이스를 구현한 클래스 nextHand( )에서의 전략 직전의 승부에서 승리했으면, 동일한 손을 내민다 직전 승부에서 패했으면, 난수를 사용해서 다음 손을 정한다. java.util.Random 클래스 이용 nextInt(3) : 0 부터 2 사이의 난수 정수 생성 어리석은 전략이다 won 필드: 지난번 승부에서 이겼으면 true, 졌으면 false 저장 prevHand 필드: 지난번 승부에서 내민 손 저장 10. Strategy /42
ProbStrategy 클래스 02. 예제 프로그램 좀 더 머리를 쓰는 전략 history 필드: 과거의 승패를 유지하는 테이블 history[이번에 내밀었던손][다음에 내밀손] 예 history[0][0]: 주먹, 주먹 순으로 손을 내밀어서 이긴 횟수 history[0][1]: 주먹, 가위 순으로 손을 내밀어서 이긴 횟수 history[0][2]: 주먹, 보 순으로 손을 내밀어서 이긴 횟수 10. Strategy /42
ProbStrategy 클래스 02. 예제 프로그램 prevHandValue 필드: 지난번에 냈던 손 currentHandValue 필드: 이번에 냈던 손 nextHand( ): 다음에 낼 손을 반환함 handValue: 다음에 낼 손의 값을 저장함 전략 이번에 주먹을 냈더라면, history[0][0], history[0][1], history[0][2]로부터 다음번에 낼 손의 확률을 계산하려고 한다. history[0][0]=3, history[0][1]=5, history[0][2]=7 이 있었다면, 세 숫자를 다 더해서(3+5+7=15) 그 값을 seed로 해서 난수를 얻음 난수가 0부터 3미만이라면, 주먹을 내고 난수가 3이상 8미만이라면, 가위를 내고 난수가 8이상 15미만이라면, 보를 낸다. 10. Strategy /42
ProbStrategy 클래스 02. 예제 프로그램 study( ) : 전략을 위한 준비 작업을 하는 메소드 이번에 이겼으면, history[직전에 냈던 손][이번에 냈던 손] 에 1을 더한다. 이번에 졌으면, history[직전에 냈던 손][이번에 안 냈던 손] 각각에 1을 더한다. 10. Strategy /42
Player 클래스 02. 예제 프로그램 가위바위보를 하는 사람을 표현한 클래스 생성 시, ‘이름’과 ‘전략’이 주어진다. 생성 시의 ‘전략’에 따라 다음에 내밀 손이 결정된다. nextHand( ) 메소드 안에서 Strategy의 nextHand( )를 호출한다. Strategy에게 위임한다. 이기든(win) 지든(lose) 무승부이든(even), 다음 승부를 위해서 Strategy의 study( ) 메소드를 호출한다. win( ), lose( ), even( ) 승패 횟수를 저장 wincount, losecount, gamecount 필드 10. Strategy /42
Main 클래스 02. 예제 프로그램 실제로 Player 둘을 생성해서 가위바위보 게임을 시킴 “Winner: “ + player1 “Winner: “ + player1.toString( ) 10. Strategy /42
ConcreteStrategy(구체적 전략)의 역할 03. 등장 역할 Strategy(전략)의 역할 Strategy 패턴을 이용하기 위한 인터페이스(API) 결정 예제에서는 Strategy 인터페이스가 해당됨 ConcreteStrategy(구체적 전략)의 역할 Strategy 인터페이스를 실제로 구현 구체적 전략(작전, 책략, 알고리즘)을 나타냄 예제에서는, WinningStrategy와 ProbStrategy가 해당됨 Context(문맥)의 역할 Strategy를 이용하는 역할 ConcreteStrategy 인스턴스를 가지고, 필요에 따라서 이를 이용함 예제에서는, Player가 해당됨 10. Strategy /42
03. 등장 역할 클래스 다이어그램 위임 => Strategy를 쉽게 교체할 수 있다 10. Strategy /42
일부러 Strategy 역할을 만들 필요가 있을까요? 04. 독자의 사고를 넓혀주는 힌트 일부러 Strategy 역할을 만들 필요가 있을까요? Strategy 역할을 구현하기만 한다면, ConcreteStrategy의 종류를 변경하기가 쉽다. 예1: 예전의 알고리즘과 개량한 알고리즘의 속도를 비교하고 싶은 경우, 간단히 교체해서 테스트할 수 있다. 예2: 장기 게임에서 사용자의 선택에 따라 사고 루틴의 레벨을 교체하는 것도 간단하게 실행할 수 있다. 실행 중에 교체하는 것도 가능하다 프로그램 동작 중에 ConcreteStrategy 역할을 교체할 수 있다 예: 메모리가 적은 환경에서는 SlowButLessMemoryStrategy를 사용하고, 메모리가 충분한 환경에서는 FastButMoreMemoryStrategy를 사용한다. 10. Strategy /42
Abstract factory 패턴 (8장) State 패턴 (19장) 05. 관련 패턴 Flyweight 패턴 (20장) Abstract factory 패턴 (8장) State 패턴 (19장) 10. Strategy /42
알고리즘(전략)을 쉽게 교체할 수 있는Strategy 패턴 06. 요약 알고리즘(전략)을 쉽게 교체할 수 있는Strategy 패턴 위임(delegation) 덕택에 가능함 10. Strategy /42
연습 문제 각자 공부할 것 10. Strategy /42