메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

Strategy 디자인 패턴 탐험하기

한빛미디어

|

2008-12-09

|

by HANBIT

11,933

제공 : 한빛 네트워크
저자 : Sean Moore
역자 : 채수원 / (블로그 doortts.tistory.com)
원문 : Exploring the Strategy Design Pattern


[역자 도입 설명]
본 글에도 나오지만 Strategy(스트래터지, 전략) 디자인 패턴은 알고리즘을 캡슐화하는 것이 기본 목적인 패턴입니다. 클라이언트의 특정 동작 방식을 상황에 따라 전략적으로 변경할 수 있게 한다는 의미에서 Strategy(전략) 디자인 패턴이라고 불리게 되었습니다. 그런데 사실 Strategy 를 ‘전략’으로 번역해 ‘전략 디자인 패턴’이라고 하면 다소 어색하게 들립니다. Strategy는 ‘스트래터지’ 이지 ‘전략’은 좀 그렇잖아! 라고 말하실 수 도 있다는 이야기 입니다. 왜 어색할까요? Singleton은 ‘싱글톤’이고, Factory 는 ‘팩터리’인 이유는 뭘까요? 자바의 메소드가 ‘방법’이라 불리지 않는 것과 일맥 상통한다 할 수 있겠습니다만, 디자인 패턴을 국내에 처음으로 소개한 번역서에서 해당 패턴의 이름을 번역하지 않고, 원문 영어 그대로 남겨놓는 식으로 번역자체를 유예해 버렸다는 것이 한 가지 큰 이유가 되었다 생각합니다. 오히려 잘 되었다 생각하실 수도 있으시겠지만, 개인적으로는 다소 아쉬움이 남는 부분입니다. :) 어쨌든, 본 번역 글에서는 Strategy가 패턴이름을 의미할 때에는 영어 원문으로, 그리고 캡슐화된 하나의 알고리즘이나 알고리즘의 선택을 이야기 할 때는 ‘전략’ 이라는 단어로 표기하였습니다. ‘전략’이란 말은 단어자체의 의미처럼 ‘어떤 일을 달성할 수 있도록 미리 세워놓은 계획’을 의미하며, 그 계획들 중 최고의 효과를 거둘 수 있는 안을 상황에 맞게 선택했느냐 못 했느냐가 전략이 유효했느냐 그렇지 않았느냐를 구분한다 하겠습니다. 그래서 다소 어색하게 들림에도 Strategy 패턴을 ‘전략’ 패턴이라 부르고자 하는 것도 같은 의미에서 입니다.
자, 도입이 다소 길었습니다. 이제부터, 벌거벗은 임금님의 옷도 볼 수 있을 것만 같은 열린 마음으로 ‘Strategy 디자인 패턴’에 대해 공부해 보도록 하겠습니다.

개요

이 글의 목적
이 글은, 당신이 Strategy(전략) 디자인 패턴에 대해 좀 더 잘 이해할 수 있도록 돕는 것을 목표로 한다. Strategy 패턴은 어떤 애플리케이션 내에서 변하지 않는 영역을 그렇지 않은 다른 부분들로부터 분리해 내기 위해 사용된다. 이 디자인패턴은 몇몇 기본 OOP 원칙들의 최상위에 자리잡고 있다. 이를테면, Strategy 패턴은 ‘구현보다는 인터페이스’ 라는 프로그래밍 개념을 사용한다. 또한, 상속보다 구성(composition, 역주1)을 선호한다. Strategy 패턴을 사용하는 이유는 어떤 클래스로부터 알고리즘을 추상화 하고, 그 알고리즘에 바탕을 둔 새로운 클래스를 만들기 위해서이다. 다형성(polymorphism)을 이용함으로써, 알고리즘들이 애플리케이션이 실행되고 있는 도중에 구성 클래스에 의해 변경될 수 있다.

(역주1) 구성(composition) : 흔히 ‘컴포지션’이라고 부른다. 특정 객체의 기능을 이용하기 위해서 해당 객체를 자신의 속성(attribute) 중 하나로 품어 안는 것을 말한다. 흔히 맴버변수(Field)로 다른 클래스 타입이 선언되어 있는 모습을 생각하면 된다.

디자인 패턴들의 해당 주제에 대해 내가 그랬던 것만큼 당신도 마찬가지로 흥미롭게 느꼈으면 한다.
자 그럼, 시작해 보도록 하자!

선수 지식

OOP 기초들
기본적인 OOP 기초들에 대해 확실히 아는 것이 본 기사를 이해하는 데에 있어 중요하다. Strategy 디자인 패턴은 OOP 핵심 개념들을 사용한다. Strategy 패턴은 OOP의 네 가지 주요 원칙들 중 세 가지에 의존한다.

(역주2) 여기서 OOP의 4대 주요원칙은 추상화, 상속, 캡슐화, 다형성을 말한다.

OOP 관련 링크:
만일 당신이 OOP 원칙들의 내용을 제대로 이해하고 있지 않다면, 다음 내용들에 대해 살펴보는 시간을 가져야 할 것이다.

ActionScript 3.0과 함께 하는 객체지향 프로그래밍
http://www.adobe.com/devnet/actionscript/articles/oop_as3.html

객체 지향
http://www.tricedesigns.com/tricedesigns_home/blog/2006/12/object-orientation.html
http:/www.tricedesigns.com/tricedesigns_home/blog/2006/12/object-orientation.html

수업: 객체 지향 프로그래밍 개념들
http://java.sun.com/docs/books/tutorial/java/concepts/

Strategy 패턴 샘플 예제들

본 기사는 두 개의 프로젝트와 함께 진행되며 모든 다이어그램들도 프로젝트 내에 함께 포함되어 있으며 다운로드가 가능하다.

AS3 Strategy (구현은 없음)
본 프로젝트는 아주 기초적인 Strategy 패턴을 정의하는 기본 AS3 프로젝트이다. 이 예제를 위한 실질적인 구현은 없다. 대신 전형적인 Strategy 패턴에서 사용되는 주요 클래스들에 대해 이해할 수 있도록 되어 있다. (추가적인 문서를 원할 경우 마찬가지로 압축파일의 as3-strategy-pattern-asdoc 디렉터리 내부를 살펴 보아라.)

AS3StrategyPatternExample.zip

데이터 매니저 클라이언트(DataManagerClient)
이 예제는 데이터를 저장하기 위해 사용되는 세 개의 서로 다른 메소드들이 어떻게 각자의 객체로 캡슐화되고 구성 클래스로 동적 할당되는지를 보여준다. 이 압축파일에는 두 개의 실행 가능한 Flex 애플리케이션이 들어있다.

DataManagerClient.zip

UML 다이어그램들
strategy-uml.zip

Strategy 패턴의 개념들

Strategy 패턴의 공식적인 정의
"4인방(Gang of Four)이 쓴 책(역주3)”에서 말하는 Strategy 패턴의 정의는 아래와 같다.
알고리즘의 군집을 정의하고, 각각을 캡슐화한 다음, 그 캡슐화한 알고리즘들을 교체 가능하게 만든다. Strategy (패턴) 은 특정 알고리즘을 이용하는 클라이언트로부터 알고리즘을 독립적으로 바꿀 수 있게 한다 – 4인방(GOF)의 디자인 패턴
이 정의는 패턴의 요소들(things)을 설명하는 걸로 시작한다. 그러나 우리는 본 기사에서 이 패턴에 대해 좀 더 깊이 살펴볼 예정이다. Strategy 패턴은 디자인 패턴 학습을 시작하기에 좋은 패턴이다. 팩토리(Factory), 데코레이터(Decorator), 컴포지트(Composite)와 이터레이터(Iterator)들은 Strategy 패턴과 함께 뒤이어 배우기에 좋은 패턴들이다.


(역주3) 4인방(Gang Of Four)으로 불리는 네 명은 Erich Gamma(현재 IBM distinguished Engineer로 활동 중), Richard Helm(현재 Boston Consulting Group에 근무 중), Ralph Johnson(일리노이 대학 컴퓨터학부 교수로 재직 중), John Vlissides(2005년 추수감사절에 44세를 일기로 생을 마감)를 말하며, 여기서 말하는 GOF의 책이란 그 네 명이 함께 쓴, IT 서적 역사상 가장 크게 성공했다고 일컬어 지는 책, 바로 “Design Patterns, Elements of Reusable Object-Oriented Software”을 지칭한다. 흔히 줄여서 “GOF책”이라고도 부른다. 참고로, GOF(Gang of Four)라는 명칭은 중국의 문화 혁명을 이끌었던 4명(모택동(毛澤東)의 부인 강청(江靑), 왕홍문(王洪文), 장춘교(張春橋), 요문원(姚文元) )을 지칭하던 단어로, 그들처럼 SW업계에서 개발의 혁명을 이끈 네 명이란 의미로 차용해 사용하게 되었다고 한다.

핵심 개념과 사용법
Strategy 패턴 뒤에 있는 개념을 이해하는 것이 몇 가지의 OOP 기본개념에 대한 이해를 증진시킬 것이다. Strategy패턴은 세 개의 핵심 OOP 개념인 “캡슐화, 상속, 그리고 다형성”으로 구성된다. 덕분에 Strategy 패턴은 해당 개념들을 학습하거나 배우기에 훌륭한 패턴이다. 이 패턴을 한 번 이해하면, 아마도 다른 프로젝트들과 특정 애플리케이션용 소스코드들 안에 있는 패턴을 알아볼 수 있게 될 것이다. Strategy 패턴은 어떤 클래스의 행동이 자주 변경되어야 하거나, 런타임 환경에서 행동이 바뀔 필요가 있을 때 사용된다. Strategy 는 상속을 여러 개 만들어야 하고, 하위 클래스들에 있는 메소드 몸체의 중복은 피하고 싶을 경우에 효과적이다. Strategy 디자인 패턴이 사용되는 또 다른 경우는 복잡한 조건문이나 분기 로직을 리팩터링 하기 위해서일 경우이다.

알고리즘을 캡슐화하기
Strategy 패턴 뒤에 있는 핵심 아이디어는 ‘한 클래스 안에 하나의 알고리즘을 캡슐화 한다’는 아이디어이다. 이들 알고리즘 기반 클래스들은 하나의 알고리즘 인터페이스의 구체적인 구현체들이 될 것이다. 이 아이디어는 알고리즘을 구현하고 있는 클래스들이 현재 사용되는 알고리즘을 동적으로 바꾸는 걸 가능하게 해주고, 그래서 구현 클래스가 제공하는 행동을 변경 가능하게 한다.

패턴 참가자들
Strategy 디자인 패턴의 주요 참가자들에 대한 개요는 아래와 같다.
  • Context 상위클래스 (Context superclass , 흐름상의 상위 클래스)
    모든 Context 하위 클래스들을 위한 메소드들과 속성들을 정의하고 해당 Context가 사용하는 strategy 인스턴스를 변경하는 메소드를 정의한다.
  • Context 하위클래스들 (Context subclasses, 흐름상의 하위 클래스들)
    전형적인 Strategy 디자인 패턴에서는, Context 클래스의 하위 클래스들이 생성될 것이다. Strategy 패턴이 사용되는 경우, 메소드의 구현내용이 하위 클래스들 사이에서 중복되진 않을 것이다. 대신, 메소드들은 그들 자신의 클래스들(혹은 “전략을 갖고 있는 클래스들strategies”)로 옮겨지게 된다.
  • 알고리즘 인터페이스 (Algorithm interface)
    알고리즘 인터페이스는 각각의 구체적인 strategy 구현체에서 이용가능한 메소드들을 정의할 것이다.
  • 구체화된 알고리즘 클래스들 (Concrete algorithm classes)
    교체 가능한 알고리즘 전략들의 집합체
  • 클라이언트 클래스(Client class)
    Context 클래스의 인스턴스와 알고리즘 구현체에 해당하는 인스턴스를 하나씩 생성한다. Context 인스턴스의 전략(strategy)을 담당하는 속성(property)에 앞서 만든 알고리즘 인스턴스를 할당한다.
핵심 패턴 다이어그램
Strategy 패턴의 순수한 형태는 아래와 같은 모습으로, 상세화된 구현이 없는 깔끔한 디자인 패턴이다. 기본적으로는 GoF 책에서 소개된 것과 동일한 다이어 그램이다. 본 글에서 소개하는 패턴의 구체화된 구현체들을 살펴 보고, 핵심 패턴을 되돌아 보는 데에 이 다이어그램이 도움을 줄 것이다.



OOP의 핵심과 Strategy
세 개의 기본적인 OOP 원칙들이 이 디자인 패턴 안에서 사용되고 있다. 그 세 개는 “캡슐화(encapsulation), 상속(inheritance), 다형성(polymorphism)” 이다. 당신은 이 패턴이 ‘상속보다는 구성(composition)’이라는 개념도 쓰고 있다고 지적할 텐데, 그게 OOP의 또 다른 핵심 개념이다.

데이터 매니저 예제

Strategy 패턴 구현 샘플
어떤 패턴에 대해 더 잘 이해하기 위해 코드 예제를 만들어 보는 것은 종종 좋은 생각이 될 수있다. 데이터 매니저 예제는 데이터를 저장하는 세 개의 서로 다른 “전략들(역주4)”을 정의하며 각각의 데이터 저장 알고리즘(혹은 전략)은 하나의 클래스 안으로 캡슐화 될 것이다. 모든 데이터 저장 전략들은 하나의 공통된 데이터 저장 알고리즘 인터페이스를 구현할 것이다. 그리고, 실제 데이터 저장 알고리즘들은 구체화된 전략 구현체들 안에서 구현될 것이다.

(역주4) 여기서 전략들(strategies)이란 전략(=알고리즘)을 담고 있는 클래스들을 지칭한다.

데이터 매니저(Data Manager) 클래스들
이 예제는 다음과 같은 클래스들로 구성되어 있다.
  • DataManagerClient
    strategy 패턴에서 사용되는 객체들을 생성하고 조립한다. setSaveDataMethod 메소드를 통해서 런타임 시에 Context 클래스들의 알고리즘을 바꿔치기 할 수 있는 옵션을 갖는다.
  • DataManager
    DataManager 클래스는 Context 클래스이다. 그리고 (Context 클래스가 그러하듯) 상위 클래스 DataManager의 변종쯤에 해당하는 하위 클래스(이를테면 ServerDataManager 클래스 같은 클래스)를 위한 클래스이다.
  • ISaveData
    이 인터페이스는 모든 구체화된 데이터 저장 전략 클래스들이 지켜야 하는 계약을 정의한다. 인터페이스 사용이 다형성을 가능케 하고, Strategy 디자인 패턴의 핵심이 된다는 점을 기억해라.
  • SaveDataToSharedObject
    이 클래스는 데이터를 Shared Object 형태로 로컬에 저장하는 알고리즘을 담고 있다. (참고: Shared Object 퍼시스턴스(persistence,역주5)를 위한 실제 코드는 본 예제에 포함되어 있지 않다) (역주5) Persistence (영속성, 영속성개체): 어떤 특정 값이나 상태를, 프로그램의 동작 순간 이외에도 영구적으로 유지할 수 있게 만들어 주는 시스템이나 개체. 쉽게 말하면 데이터를 저장하고 있는 파일(시스템)이나 DBMS 등이 이에 해당한다.
  • SaveLocalSQLiteData
    이 클래스는 데이터를 로컬 SQLite 데이터베이스에 저장하는 알고리즘을 담고 있다.(참고: SQLite 퍼시스턴스를 위한 실제 코드는 본 예제에 포함되어 있지 않다.) 이 알고리즘은 어도비 AIR 기반 애플리케이션에서만 사용 가능하게 될 것이다.
  • SaveServerSideData
    이 클래스는 데이터를 서버 사이드 데이터 퍼시스턴스(persistence) 매커니즘에 저장하는 알고리즘을 담고 있다. (참고: 서버 사이드 퍼시스턴스용 실제 코드는 본 예제에 포함되어 있지 않다.).
  • MessageLogger
    메시지 로깅 클래스는 예제에서 실행 정보 표시를 도와주는 매우 간단한 클래스이다.
데이터 저장 “전략들”
각각의 알고리즘을 (특정한) 하나의 클래스로 옮기는 것은 해당 알고리즘을 사용하는 어떠한 클래스로부터든, 알고리즘의 독립적인 업데이트를 가능케 한다. 이런 방식은, 여러 개의 하위 클래스들이 있는 상위 클래스를 갖고 있고, 각각의 서브 클래스들에 있는 알고리즘들용 메소드들은 내장하고 싶지 않은 경우에 유용하다.

인터페이스 사용으로 다형성 이루기
데이터 매니저 예제에서 ISaveData 인터페이스는, 모든 구현 클래스들에서 선언되어야 하는 메소드들을 정의한다. 다시 말해, 이것이 다형성의 핵심 개념 중 하나이다. ISaveData인터페이스의 구체적인 구현체들을 이용하는 클래스들, 다시 말해 구상 클래스들은 런타임 시에 사용하던 ISaveData 구현체를 다른 구현체로 변경할 수 있다.

세 개의 데이터 저장 전략
데이터 매니저 예제는 세 개의 구체화된 ISaveData 인터페이스 구현체들을 갖고 있다. SaveServerSideData, SaveLocalSQLiteData , 그리고 SaveDataToSharedObject 가 바로 그 세 개이다. 예제에서 이들 구현체들은 내용이 비어 있긴 하지만 데이터 저장 알고리즘들이 위치할 장소가 된다. 이 시점에서 Strategy 패턴의 강점이 명확해 지기 시작해야 한다. :) 이들 알고리즘을 활용하는 클래스들은, 원할 때는 언제든지 데이터 저장 전략을 바꿀 수가 있다.



전략 변경하기
데이터 매니저 예제에서 Context 클래스에 해당하는 클래스는 DataManager 클래스이다. DataManager 클래스는 setSaveDataMethod 메소드를 정의하고 있는데, 이 것이 Strategy 패턴을 구축하기 위해 필요한 또 다른 핵심 요소이다. 이를 통해 애플리케이션 동작 중에 DataManager의 인스턴스들이 데이터 저장 메소드의 ‘전략(=알고리즘)’을 변경할 수 있게 된다. 이것이 바로 인터페이스를 사용하는 이유이며, 또한 해당 인터페이스의 구체화된 구현체들(concrete implementations) 을 만드는 이유가 된다.

데이터 매니저 예제 실행하기


[DataManagerClient를 실행시킨 모습]

데이터 매니저 예제를 실행하면, 간단한 애플리케이션이 보여지고 거기에는 세 개의 라디오 버튼 컨트롤이 애플리케이션 뷰에 보여진다. 라디오 버튼들 중 하나가 선택될 때 클라이언트는 DataManager 인스턴스가 사용하는 데이터 저장 알고리즘을 변경한다. 예제에서 각각의 알고리즘 클래스는 TextArea 로 보내는 고유한 메시지를 갖고 있다. TextArea 에서 보이는 메시지는 Save 버튼을 누를 때 변경될 것이다. 애플리케이션을 실행해서 한번 테스트 해 보아라. 애플리케이션의 코드는 추후에 좀 더 자세히 살펴볼 예정이다.

DataManager 클래스 코드 살펴보기
DataManager.as 소스코드를 살펴보자.
package com.seantheflexguy.dataManager
{
 	import mx.collections.ArrayCollection;
 	
 	public class DataManager
 	{
  		
  		private var saveDataMethod:ISaveData;
  		
  		public function DataManager()
  		{
   		}
  		
  		public function setSaveDataMethod(newMethod:ISaveData):void
  		{
   			saveDataMethod = newMethod;
   		}
  		
  		public function save(dataCollection:ArrayCollection):void
  		{
   			saveDataMethod.save(dataCollection);
   		}
  
  	}
}
이 클래스는 앞서 실행한 애플리케이션 내에서 데이터 관리의 기반이 되는 클래스이다. 이어지는 예제에서 이 클래스가 어떻게 확장되어지고, 데이터 저장 행동방식이 어떻게 각자의 클래스로 분리되는지를 보게 될 것이다. setSaveDataMethod 메소드에 주목해라. 이 메소드는 newMethod라는 ISaveData 데이터 타입을 인수로 받아들인다. 데이터 저장 알고리즘의 실제 타입은 기존의 데이터 저장 알고리즘 중 하나가 될 수 도 있고, 새로운 알고리즘이 될 수도 있다. 실제DataManager 는 수정하지 않아도 된다는 사실을 명심해라. 마찬가지로, 하위 클래스들도 데이터 저장 알고리즘의 동작방식을 바꾸기 위해 수정을 가하지 않아도 된다. 알고리즘들은 교체가 가능하다. save 메소드는 데이터 저장 알고리즘의 save 메소드를 호출하고 저장할 데이터를 save 메소드의 인수(dataCollection:ArrayCollection)로 넘겨준다.

ISaveData 인터페이스 코드 살펴보기
ISaveData.as 에서 정의된 인터페이스는 단순하지만, 매우 효과적이다.
package com.seantheflexguy.dataManager
{
 	import mx.collections.ArrayCollection;
 	
 	public interface ISaveData
 	{
  		function save(dataCollection:ArrayCollection):void;
  	}
}
ISaveData 인터페이스에서 save메소드를 정의하는 것은 일종의 계약을 작성하는 것이다. 그리고, 그 계약이란 이 인터페이스를 구현하는 모든 클래스들이 반드시 지켜야 하는 계약을 의미한다. 이로 인해 구체화된 ISaveData 구현체들의 다형성 구현이 가능하게 된다.

SaveServerSideData 클래스 코드 살펴보기
ISaveData 인터페이스의 구체적인 구현은 아래와 같다.
package com.seantheflexguy.dataManager
{
 	import mx.collections.ArrayCollection;
 	import mx.utils.ObjectUtil;
 	
 	
 	public class SaveServerSideData implements ISaveData
 	{
  		public function SaveServerSideData()
  		{
   		}
  
  		public function save(dataCollection:ArrayCollection):void
  		{
   			MessageLogger.log(">>save: SaveServerSideData - "+
   					    "save data to a remote server, "+
   					    "perhaps a database.");
   			MessageLogger.log(">>save: dataCollection: n"+
   					    ObjectUtil.toString(dataCollection));
   			// ...
   		}
  		
  	}
}
ISaveData 를 구현한 클래스를 주의 깊게 보라. 실제적인 데이터 퍼시스턴스 알고리즘은 예제에서 생략되어 있다. (데이터 퍼시스턴스는 본 글의 범위를 벗어나므로 여기에서는 다루지 않는다.)

SaveLocalSQLiteData 클래스 코드 살펴보기
ISaveData 인터페이스의 또 다른 구체적인 구현모습은 아래와 같다.
package com.seantheflexguy.dataManager
{
 	import mx.collections.ArrayCollection;
 	import mx.utils.ObjectUtil;
 	
 	public class SaveLocalSQLiteData implements ISaveData
 	{
  		public function SaveLocalSQLiteData()
  		{
   		}
  
  		public function save(dataCollection:ArrayCollection):void
  		{
   			MessageLogger.log(">>save: SaveLocalSQLiteData - "+
   					    "save data to a local SQLite database. " + 
   					    "this strategy could only be used for "+
   					    "AIR based applications.");
   			MessageLogger.log(">>save: dataCollection: n"+
   					    ObjectUtil.toString(dataCollection));
   			// ...
   		}
  		
  	}
}
이 클래스는 데이터를 로컬 SQLite 데이터베이스에 저장하기 위해 필요한 알고리즘을 포함하고 있다. 물론, 이 알고리즘은 어도비 AIR 애플리케이션에서만 사용되어야 한다. 왜냐하면 SQLite는 Flex 애플리케이션에선 곧장 사용할 수 없기 때문이다. 다시 한번 이 부분에서 Strategy 패턴 뒤에 숨어있는 논리를 눈치채기 시작할 것이다. 데이터 저장 “알고리즘/전략” 중 하나는 애플리케이션이 “배포/온라인” 상태에 있을 때 사용되고, 또 다른 데이터 저장 “알고리즘/전략”은 애플리케이션이 “로컬/데스크탑” 상태일 때 사용된다.

SaveDataToSharedObject 클래스 코드 살펴보기
ISaveData 인터페이스의 구체적인 구현이 아직 하나 더 남아있다.
package com.seantheflexguy.dataManager
{
 import mx.collections.ArrayCollection;
 import mx.utils.ObjectUtil;
 	
   public class SaveDataToSharedObject implements ISaveData
   {
 	public function SaveDataToSharedObject()
  	{
   	}
  
 	public function save(dataCollection:ArrayCollection):void
 	{
 		MessageLogger.log(">>save: SaveDataToSharedObject - "+
 				    "save data to a local shared object.");
 		MessageLogger.log(">>save: dataCollection: n"+
 				    ObjectUtil.toString(dataCollection));
   			// ...
   	}
  		
  }
}
만약 데이터가 로컬에 저장되어야 한다면 이 구현체를 애플리케이션의 “배포/온라인” 버전에서 사용 할 수 있다.

DataManagerClient MXML 파일 살펴보기
DataManagerClient MXML 은 Strategy 패턴의 조각들을 한 곳으로 모아주는 실행 가능한 Flex 애플리케이션이다.


	
		
	
	
	
	
	
	
	

클라이언트는 데이터 저장용 ‘전략’을 한데 모아놓고, DataManager 인스턴스가 사용할 전략을 변경할 수 있는 시각적인 방법을 제공한다. 애플리케이션을 실행시켜서, 저장 알고리즘을 변경하기 위해서 각기 다른 라디오 버튼 중 하나를 선택한 다음, “Save” 버튼을 누를 때에, UI Form 에 각각 다른 로깅 메시지가 쓰여지는 것을 보아라.


[실행 초기 화면]


[버튼을 선택하고 Save 버튼을 누른 상태]

슈퍼클래스인 DataManager
DataManager 클래스의 하위 클래스 들은 또한 Strategy 패턴내에서 정의된 관계형식의 장점을 누릴 수 있다. 다음 예제인 Server Data Manager는 DataManager 의 하위 클래스들이 어떻게 생성될 수 있는지, 그리고 이미 만들어져 있고 정의되어 있는 서로 다른 데이터 저장 알고리즘들을 어떻게 이용할 수 있는지를 확실히 보여줄 것이다. 마찬가지로 또한, 미래에 새로운 전략들이 추가될 수도 있다는 점을 명심해라.

서버 데이터 매니저 예제

DataManager 의 하위 클래스를 만들기
이 샘플 시나리오에서는, 프로젝트의 고객으로부터 ‘데이터를 서버 측에 저장하는 기능을 갖고 있으며 그 이외에는 어떤 다른 일도 하지 않는 애플리케이션을 생성 하는 것’을 요청 받았다고 가정한다. 이런 경우가 바로 Strategy 패턴이 초점을 맞추고 있는 또 다른 부분이다. 우리는 프로젝트 고객의 요구사항을 만족시키기 위해서 DataManager 의 하위 클래스를 하나 만들 수 있다. 그 하위 클래스는 DataManager 클래스의 간략화 버전이 될 것이고, 비록 DataManager에 필요 없는 속성값 들을 담게 되긴 하겠지만, 런타임 시에 저장 방식을 교체하는 능력을 포함해서 우리가 DataManager 에서 원했던 기능들도 마찬가지로 갖게 된다.

서버 데이터 매니저 클래스들
본 예제는 다음과 같은 클래스들로 구성된다.
  • ServerDataManagerClient
    strategy 패턴에서 사용될 객체들을 만들고 조립한다. 예제에서 이 클라이언트는 전략들을 변경하진 않을 것이다. 하지만, 그렇게 할 수 있는 능력은 가지고 있다. 사실, 서버 쪽에 데이터를 저장하는 새로운 알고리즘이 만들어질 수 있고, 그 새로운 알고리즘이 setSaveDataMethod 메소드 호출을 통해ServerDataManagerClient 클래스에서 사용될 수도 있다. setSaveDataMethod 메소드는 새로운 서버 사이드 데이터 저장 알고리즘을 포함하고 있는 새로운 구체화된 전략 클래스의 인스턴스를 넘겨받게 될 것이다.
  • ServerDataManager
    ServerDataManager 클래스는 DataManager 의 하위 클래스이다. ServerDataManager 클래스는 구체적인 ISaveData의 구현 클래스의 인스턴스를 저장하기 위한 구성(composition)에 의존한다.
  • ISaveData
    이 인터페이스는 모든 구체화된 데이터 저장 전략 클래스들이 지켜야 하는 계약을 정의한다. 인터페이스 사용이 다형성을 가능케 하고, Strategy 디자인 패턴의 핵심이 된다는 점을 기억해라.
  • SaveServerSideData
    이 클래스는 데이터를 서버 측 데이터 영속성(persistence) 매커니즘에 저장하는 알고리즘을 갖고 있다. (참고: 서버 사이드 퍼시스턴스용 실제 코드는 본 예제에 포함되어 있지 않다.).
  • MessageLogger
    메시지 로깅 클래스는 예제에서 실행 정보 표시를 도와주는 매우 간단한 클래스이다.
서버 데이터 매니저 클라이언트
Strategy 디자인패턴을 구현하는 해당 클라이언트는 SaveServerSideData 객체를 생성하는 ServerDataManager 객체 의 인스턴스용 save 메소드를 설정할 것이다. 클라이언트는 향후 데이터 저장 전략을 바꿀수 있는 능력을 갖고 있다. 지금은 단지 SaveServerSideData 전략만을 사용할 예정이다.



ServerSideDataManager 클래스 코드 살펴보기
본 클래스는 상위클래스 DataManager 의 하위 클래스이다.
package com.seantheflexguy.dataManager
{
 	public class ServerDataManager extends DataManager
 	{  		
  		public function ServerDataManager()
  		{
   			super();
   		}  		
  		public function pingServer():void
  		{
   			MessageLogger.log(">>pingServer: ServerDataManager - "+
   					    "ping the remote server.");
   			//...
   		}		
  	}
}
저장 알고리즘을 수행하는 실제 코드가 상위 클래스인 DataManager에도, 하위 클래스에 해당하는 ServerSideDataManger 에도 들어있지 않다는 것을 눈치챘을 것이다. (두 클래스 안에 들어가 있는) 대신에, 알고리즘은 자기 자신에 해당하는 클래스로 옮겨져서는, 공통 인터페이스를 구현하고 있다. 이 공통 인터페이스는 DataManager 와 ServerSideDataManager 가 알고리즘을 사용하거나, 실행하고자 하는 알고리즘으로 교체하는 것을 원할 때면 언제든 가능하게 만들었다.

ServerSideDataManagerClient MXML 파일 살펴보기
ServerSideDataManagerClient MXML 은Strategy 패턴의 조각들을 한 곳으로 모아주는 실행 가능한 Flex 애플리케이션이다. 이 애플리케이션은 데이터가 오로지 원격 데이터 베이스에서만 영속성을 갖게 만들어 주는 DataManager 의 간략화 버전이다. 데이터를 서로 다른 종류의 원격 데이터 베이스에 저장하기 위한 새로운 전략들을 만들어 내는 것이, Strategy 디자인 패턴을 사용함으로써 어떻게 달성 가능해 질지에 대해 잠시 생각해 보는 시간을 갖자.


	
		
	
	
	
	

이 애플리케이션은 데이터 매니저 클라이언트와 거의 똑같다. 하지만 이 애플리케이션에서는 데이터 저장 전략을 바꾸는 것이 전혀 의미가 없다는 점에 주시해라. 훗날 서로 다른 원격 데이터 베이스에 데이터를 저장하는 알고리즘 구현이 필요해 질 수도 있다. 혹은 이 애플리케이션을 어도비(Adobe) AIR 모드에서 로컬 SQLite 데이터 베이스에 저장 가능하도록 만들 필요가 생길 수도 있다. 애플리케이션이 스스로 생명이 다할 때까지 맞닥뜨리게 될 변경 사항들이란 결코 끝이 없고, 대비 한다는 것도 쉽지 않다. 다만, 디자인 패턴들을 사용해 당신의 코드들을 꾸준히 성장케 하고 발생할 수 밖에 없는 변경에 대해 준비해 놓도록 도울 수는 있다. 이 글의 현재 시점에서, 부디 당신은 이 특별한 패턴의 몇 가지 장점들에 대해 알아가기 시작하는 중 이길 바란다.

정리

한 곳으로 모으기
멀찌감치서 모든 것들을 전체적으로 되돌아 보면, 끌어안고 가야 하는 수많은 핵심 개념들이 보인다. 알고리즘을 분리시켜서 한 클래스 안으로 캡슐화 한다는 개념은 기본적으로 사용되는 개념이다. 또한 “변하는 것을 캡슐화해라”라는 말은, 전략 인터페이스와 구체화된 구현체들로 다형성을 사용하라는 것이다. Server Data Manager예제는 어떻게 하면 메소드 그룹을 상위 클래스의 메소드나 하위 클래스의 메소드로부터 깔끔하게 분리시킬 수 있는지를, 그래서 어떻게 메소드의 구체적인 내용들이 손쉽게 변경가능한지를 풀어서 보여준다.

요약
나는 이 글이 Strategy 패턴의 강력함에 대한 통찰과 당신이 작성하는 애플리케이션에서 좀더 많이 디자인 패턴들을 사용하게 하는 열린 창을 제공했으면 한다. 디자인 패턴의 이점을 갖는 애플리케이션 소스코드들은 수정하거나 유지하기에 종종 더 쉽다. 그리고 그런 코드들은 마찬가지로 미래의 변경에 좀 더 어려움 없이 대할 수 있다. 샘플 애플리케이션, 그리고 UML 다이어그램들을 반드시 다시 한번 살펴보는 시간을 갖길 바란다. 다이어그램들과 코드 예제들로 구성된 이 글은, 당신의 작업물 내에서 Strategy 패턴을 쓸 수 있도록 해 줄 것이다.

추가 정보

웹페이지:

Strategy 패턴
위키피디아(Wikipedia)
http://en.wikipedia.org/wiki/Strategy_pattern

Strategy UML 다이어그램 –GoF 버전
http://www.tml.tkk.fi/~pnr/GoF-models/html/Strategy.html

자바 디자인패턴 전략
www.fluffycat.com
http://www.fluffycat.com/Java-Design-Patterns/Strategy/

Strategy
www.dofactory.com
http://www.dofactory.com/Patterns/PatternStrategy.aspx#_self1

책들:

Design Patterns: Elements of Reusable Object-Oriented Software
(디자인 패턴: 재사용 가능한 객체 지향 소프트웨어의 요소들)
Addison-Wesley Professional - Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides
http://www.informit.com/store/product.aspx?isbn=0201633612

Head First Design Patterns(헤드 퍼스트 디자인 패턴)
O"Reilly Media, Inc.: Eric Freeman, Elisabeth Freeman, Kathy Sierra, Bert Bates
http://oreilly.com/catalog/9780596007126/

ActionScript 3.0 Design Patterns
O"Reilly Media, Inc.: William B. Sanders, Chandima Cumaranatunge
http://oreilly.com/catalog/9780596528461/

Refactoring to Patterns(패턴을 활용한 리팩터링)
Addison-Wesley Professional: Joshua Kerievsky
TAG :
댓글 입력
자료실