'2009/06'에 해당되는 글 3건
- 2009/06/19 Strategy Pattern
- 2009/06/12 Observer Pattern (수정) (2)
- 2009/06/11 Observer Pattern
간단하게 책에서 정의한 내용을 보면..
정의만으론 뭔가 확 다가오지 않죠?..^^;; 이제 차근차근 예제를 들어 보겠습니다.
우선 Strategy Pattern 은 어떤 경우에 사용하는게 좋을까요? 제가 생각해본 예는 여러 드로잉툴의 "저장"을 하는부분입니다.
한 예로 포토샵을 생각해보면 우리는 새창을 띄워서 작업을 한 후에 저장을 하게 되는데요.. 유저는 저장을 할때 포맷을 지정하여 저장하게 됩니다. jpg, png, bmp 등이 있겠죠?. 그래서 여러 포맷으로 저장하는 방법을 알고리즘군으로 정의하게 됩니다.
그럼 저장 알고리즘의 인터페이스를 볼까요.
package
{
public interface ISave
{
function save(): void
}
}
저장인터페이스의 기능은 각각 실행해야하는 포맷들의 저장 로직군을 대변하고 있죠. 또한 이렇게 추상화함으로써 클라이언트에서는 저장이란것만 알고 있고 어떠한 저장포맷들이 있는지 몰라도 되게 됩니다.다음은 저장알고리즘들의 구상클래스입니다. 차례대로 jpg저장, bmp저장, png저장입니다.
package
{
public class SaveForJpeg implements ISave
{
public function SaveForJpeg()
{
}
public function save(): void
{
trace("Jpeg 포맷으로 저장합니다.");
}
}
}
package
{
public class SaveForBmp implements ISave
{
public function SaveForBmp()
{
}
public function save(): void
{
trace("Bmp 포맷으로 저장합니다.");
}
}
}
package
{
public class SaveForPng implements ISave
{
public function SaveForPng()
{
}
public function save(): void
{
trace("Png 포맷으로 저장합니다.");
}
}
}물론 jpg로 저장하는데 save()로 끝나진 않겠죠...여러 인자들이 들어가겠죠? ^^;;..다음은 DrawingTool 클래스입니다.
package
{
public class DrawingTool
{
protected var kindOfSave:ISave;
public function DrawingTool()
{
}
public function display(): void
{
throw new Error("오버라이드 오네가이시마스");
}
public function performSave(): void
{
kindOfSave.save();
}
public function setKindOfSave(_kindOfSave:ISave): void
{
kindOfSave = _kindOfSave;
}
}
}
드로잉툴이라면 갖춰야 할부분들을 구현합니다. 또한 저장기능을 구체적으로 선언하지 않고 추상형으로 하여 유연하게 바꿀수 있게 하였습니다.다음은 PhotoShop 클래스입니다. 이부분도 Strategy Pattern의 장점이라고 생각되는데요. PhotoShop뿐만 아니라 Illurstrator등 다른 드로잉프로그램에서도 적용하여 저장기능을 사용할 수 있을 거라고 생각합니다.
package
{
public class PhotoShop extends DrawingTool
{
public function PhotoShop()
{
kindOfSave = new SaveForJpeg();
}
public override function display(): void
{
trace("저는 포토샵입니다. ^^;;");
}
}
}
마지막으로 Main에서는 드로잉툴을 등록하고 저장을 실행시키고, 새로운 포맷으로 교체해서 저장도 할 수 있게 해줍니다.
package {
import flash.display.Sprite;
public class Main extends Sprite
{
public function Main()
{
var photoShop:DrawingTool = new PhotoShop();
photoShop.display();
photoShop.performSave();
photoShop.setKindOfSave(new SaveForPng());
photoShop.performSave();
}
}
}
음... 위에서는 저장만을 가지고 예를 들었지만. 로드하는 부분도 똑같이 쓸 수 있다고 생각합니다. 그러면 포맷별로 로드하는 방법을 알고리즘군으로 만들고 ILoad 인터페이스를 구현해서 만들면 될거 같습니다. ^^;
마지막으로 제가 생각한 장점을 살짝 정리를 하자면. 새로운 포맷이 추가될때는 ISave에 맞춰서 그에 맞는 포맷구상클래스를 만들어 주어 확장성을 열어주는 점. 또한 저장이나, 로드등 이러한 기능들을 드로잉툴이라면 새로 구현하지 않아도 쉽게 가져다가 쓸 수 있을거라는 생각을 하게 되었습니다.
음..실제로 구체적으로 구현한것이 아니라 trace로 엉성한 마무리를 지었습니다...^^;; 괜찮은 예제를 또 생각해보고 직접 구현해보아야겠어요. 실제로 부딪히는 문제들이 많을테니까요.. :ㅇㄷㄷ 그럼 이상 Strategy Pattern 이었습니다.(__)
'Design Pattern' 카테고리의 다른 글
| Strategy Pattern (0) | 2009/06/19 |
|---|---|
| Observer Pattern (수정) (2) | 2009/06/12 |
| Observer Pattern (0) | 2009/06/11 |
옵저버패턴...수정에, 수정.. 최대한 이해될때까지!! 어제 올린 것에서 수정한 부분만 올려봅니다.
package
{
public interface ISubject
{
function addObserver(_observer:AbstractObserver): void
function removeObserver(_observer:AbstractObserver): void
function notifyObservers(): void
function setData(_item:Array): void
function start(): void
}
}
"네이버실시간인기검색어를 타이머 인터벌로 제공해주는 서브젝트" 란 임무를 맡은 subject 이기 때문에 클래스 네이밍도 바꿔봤구요.. 이름에 걸맞게 이녀석에게 타이머를 핸들하는 부분도 맡게 해주었습니다. 그리고 API부분은 기존에 INaverSubject 인터페이스는 삭제하고 NaverSearchSubject 도 네이밍을 NaverPopSearchWord 로 바꾸어주고 subject 에서 선언해주었습니다. 타이머를 이용해서 새로운 검색어를 얻어오는 부분은 전부 이곳에서 진행됩니다!.
package
{
import flash.events.TimerEvent;
import flash.utils.Timer;
public class NaverSearchData_on_TimerInterval implements ISubject
{
private var item:Array;
private var observerArray:Array;
private var naverData:NaverPopSearchWord;
private var timer:Timer;
private var init_flag:Boolean = true;
public function NaverSearchData_on_TimerInterval(): void
{
init();
}
private function init(): void
{
naverData = new NaverPopSearchWord();
timer = new Timer(1000, 5);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
timer.start();
observerArray = new Array();
}
public function addObserver(_observer:AbstractObserver):void
{
observerArray.push(_observer);
}
public function removeObserver(_observer:AbstractObserver):void
{
var numberOfObserver:uint = observerArray.indexOf(_observer);
if (numberOfObserver >= 0)
{
observerArray.splice(numberOfObserver, 1);
}
}
public function notifyObservers():void
{
for each (var observer:AbstractObserver in observerArray)
{
observer.update(item);
}
}
public function setData(_item:Array):void
{
this.item = _item;
notifyObservers();
}
public function start(): void
{
naverData.initialize();
}
private function timerHandler(e:TimerEvent): void
{
if (init_flag)
{
setData(naverData.getData());
init_flag = false;
}
}
private function timerCompleteHandler(e:TimerEvent): void
{
naverData.initialize();
setData(naverData.getData());
timer.start();
}
}
}
subject 에서 타이머를 가지고 가는바람에 메인이 간단해졌습니다 +_+;
package
{
import flash.display.Sprite;
import flash.text.TextField;
public class Main extends Sprite
{
public function Main(): void
{
init();
}
private function init(): void
{
var searchData:ISubject = new NaverSearchData_on_TimerInterval();
var searchDisplay:AbstractObserver = new FavoriteSearchDisplay();
searchData.addObserver(searchDisplay);
searchData.start();
addChild(searchDisplay);
}
}
}
음.. 여러모로 부족하기 때문에 최대한 이해를 하는게 저의 목표입니다. 또한 한번 더 생각해보기. 계속해서 물음표를 던져보기..으쌰!! 다음 패턴은 지금 책을 3~4번 읽고 있는데 좀만 더 읽어보고..^^;; 옵저버패턴과 마찬가지고 책의 예제로 정리후 알맞은 예제를 선택해봐야겠습니다.
'Design Pattern' 카테고리의 다른 글
| Strategy Pattern (0) | 2009/06/19 |
|---|---|
| Observer Pattern (수정) (2) | 2009/06/12 |
| Observer Pattern (0) | 2009/06/11 |
package
{
public interface ISubject
{
function addObserver(_observer:AbstractObserver): void
function removeObserver(_observer:AbstractObserver): void
function notifyObservers(): void
function setData(_item:Array): void
}
}
다음은 호스트가 많이 알고 있을필요 있을까?! 해서 OpenAPI를 쓰는 부분을 모조리 뺐습니다. 나름 인터페이스를 만들어서 했는데..이부분도 왠지 자신이 없다는;;; 음 일단 이렇게 해서 호스트에서 NaverSearchSubject 라는 녀석으로 빼는 작업을 했습니다.
package
{
public interface INaverSubject
{
function initialize(): void
function getData(): Array
}
}
다음은 3번에 관한 부분입니다. 옵저버를 추상인터페이스로 구현하지 않고 추상클래스로 상속받게 하려고 만든 클래스입니다.
package
{
import flash.display.Sprite;
public class AbstractObserver extends Sprite
{
public function AbstractObserver(): void { }
public function update(_item:Array): void { }
}
}
package
{
public interface IDisplayElement
{
function display(): void
}
}
이부분은 특별히 바뀐건 없고 옵저버를 AbstractObserver 를 상속받게 하였습니다.
package
{
public class FavoriteSearchDisplay extends AbstractObserver implements IDisplayElement
{
private var item:Array;
public function FavoriteSearchDisplay()
{
}
public override function update(_item:Array): void
{
this.item = _item;
display();
}
public function display(): void
{
for (var i:Number = 0; i < item.length; i++)
{
parent["text" + i].text = (i + 1) + ". " + item[i];
}
}
}
}
역시 이부분도 바뀐 부분은 없습니다..;
package
{
public class SearchData implements ISubject
{
private var item:Array;
private var observerArray:Array;
public function SearchData()
{
observerArray = new Array();
}
public function addObserver(_observer:AbstractObserver):void
{
observerArray.push(_observer);
}
public function removeObserver(_observer:AbstractObserver):void
{
var numberOfObserver:uint = observerArray.indexOf(_observer);
if (numberOfObserver >= 0)
{
observerArray.splice(numberOfObserver, 1);
}
}
public function notifyObservers():void
{
for each (var observer:AbstractObserver in observerArray)
{
observer.update(item);
}
}
public function setData(_item:Array):void
{
this.item = _item;
notifyObservers();
}
}
}
네. 이부분이 바로 기존의 호스트에 있던 API부분을 띄어낸 부분입니다. 특별히 수정한부분은 없고 Array데이터를 얻어올 수 있게 getData메소드를 만들어 주었습니다.
package
{
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
public class NaverSearchSubject implements INaverSubject
{
private var url:String = "네이버API주소";
private var urlLoader:URLLoader;
private var request:URLRequest;
private var dataArray:Array;
private var xml:XML;
public function NaverSearchSubject(): void
{
urlLoader = new URLLoader();
request = new URLRequest(url);
}
public function initialize(): void
{
urlLoader.load(request);
urlLoader.addEventListener(Event.COMPLETE, loadCompleteHandler);
}
private function loadCompleteHandler(e:Event): void
{
dataArray = new Array();
xml = XML(e.target.data);
var childItems:XMLList = XMLList(xml.item.children().child(0));
for each (var itemList:String in childItems)
{
dataArray.push(itemList);
}
}
public function getData(): Array
{
return dataArray;
}
}
}
마지막으로..메인입니다. 음. 확실히 API부분을 떼어버리니 깔끔한것 같네요...+_+;;; 일단 구상클래스를 추상형으로 선언하였습니다.음..그리고 다른건 없고 5초마다 NaverSearchSubject 녀석한테서 data를 얻어와서 주제녀석에게 알려주게 했습니다..
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.text.TextField;
import flash.utils.Timer;
public class Main extends Sprite
{
private var searchData:ISubject;
private var searchDisplay:AbstractObserver;
private var naverData:INaverSubject;
private var timer:Timer;
private var init_flag:Boolean = true;
public function Main()
{
init();
timer = new Timer(1000, 5);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler);
timer.start();
}
private function init(): void
{
naverData = new NaverSearchSubject();
searchData = new SearchData();
searchDisplay = new FavoriteSearchDisplay();
naverData.initialize();
searchData.addObserver(searchDisplay);
addChild(searchDisplay);
}
private function timerHandler(e:TimerEvent): void
{
if (init_flag)
{
searchData.setData(naverData.getData());
init_flag = false;
}
}
private function timerCompleteHandler(e:TimerEvent): void
{
naverData.initialize();
searchData.setData(naverData.getData());
timer.start();
}
}
}
이상. 옵저버패턴을 이용한 실시간검색순위 수정버전이었습니다...^^;;;; 정신없이 했더니 잘되었는지 모르겠네요..ㅠ..ㅠ 허접하나 보시는분들은 참고가 되시길. 그리고 지적 또한 부탁드립니다.(__)..아웅 졸립군요..zZ'Design Pattern' 카테고리의 다른 글
| Strategy Pattern (0) | 2009/06/19 |
|---|---|
| Observer Pattern (수정) (2) | 2009/06/12 |
| Observer Pattern (0) | 2009/06/11 |


