'2009/06'에 해당되는 글 3건

  1. 2009/06/19 Strategy Pattern
  2. 2009/06/12 Observer Pattern (수정) (2)
  3. 2009/06/11 Observer Pattern

Strategy Pattern

|
이번에는 Strategy Pattern 에 대해서 좀 적어보려고 합니다.
간단하게 책에서 정의한 내용을 보면..

Strategy Pattern 에서는 알고리즘군을 정의하고 각각을 캡슐화하여 교환해서 사용할 수 있도록 만든다. 스트래티지를 활용하면 알고리즘을 사용하는 클라이언트와는 독립적으로 알고리즘을 변경할 수 있다. -  Head First -

정의만으론 뭔가 확 다가오지 않죠?..^^;; 이제 차근차근 예제를 들어 보겠습니다.
우선 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
Trackback 0 And Comment 0

Observer Pattern (수정)

|

옵저버패턴...수정에, 수정.. 최대한 이해될때까지!! 어제 올린 것에서 수정한 부분만 올려봅니다.
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
Trackback 0 And Comment 2

Observer Pattern

|




음. 히카님께서 지적해주신대로 수정해보려고 했는데 잘 되었는지는 잘 모르겠지만.. 이해가 느린저로써 일단 요기까지 해보았습니다. 왠지 하나가 덜끝난 상태에서 다른 패턴으로 넘어가면 찝찝해서 최대한 생각할 수 있을 때가지 해보고 다음으로 넘어가겠습니다. 일단 ISubject 인터페이스에 setData를 추가했는데요. 이부분은 호스트에서 주제녀석을 추상형으로 지정하다보니 추가하게 되었습니다..
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
Trackback 1 And Comment 0
prev | 1 | next