일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- Winform
- eventhandler
- MDB Connect
- 디자인 패턴
- C# MDB
- sqlite3
- WPF
- Json.NET
- 버스 API
- 경기도 버스정보시스템
- MDB Select
- 객체지향
- solid
- TDD
- 시
- GDI+
- MVC
- DrawEllipse
- Excel Cell Format
- C# 파일 암/복호화
- NUnit
- JSON
- 경기도 버스
- delegate
- DrawRectangle
- Cell Border Style
- eventargs
- c#
- C# MDB Handle
- 공공 데이터 포털
- Today
- Total
White Whale Studio
Decorator Pattern (데코레이터 패턴) 본문
이 패턴은 처음에는 이해하기가 난해했던 패턴입니다.
라고 하는데 이름에서 어느정도 유추를 할 수 있는것처럼
Decorate : 꾸미다. 장식하다.
라는 의미를 가집니다.
즉, 특정 객체가 있으면 데코레이터를 통해 기능을 추가하는(장식하는) 것이 가능합니다.
위임/상속으로 구현되어 감싸는 데코레이터의 개수에는 제한이 없습니다.
간단한 예를 들어볼까요.
크리스마스가 되면 집집마다 분위기를 내기 위해 크리스마스 트리를 장식합니다.
이 크리스마스 트리를 장식하는 것을 빗대어 보면
객체는 크리스마스 트리, 데코레이터는 트리에 장식을 달기 위한 규칙(추상 클래스), 트리에 달기 위한 장식품들은
데코레이터 클래스가 되는 겁니다.
데코레이터 패턴에 대한 내용들을 몇 군데서 살펴보니 커피와 커피에 추가로 들어가는 모카라던가 우유거품, 두유 등의 예시를 든 예제들이 많았습니다.
그 중에서 제가 보기엔 가장 이해하기 쉬웠던 예제를 가져왔습니다.
위의 도표에서 살펴보면 Beverage 아래에 있는 DarkRoast, Decaf 등이 꾸며질 대상이 되는 객체이고
우측의 CondimentDecorator는 추상 클래스, 그 아래에 있는 Mocha, Soy, SteamMilk, Whip이 데코레이터 클래스가 됩니다.
근본적으로는 추상 클래스인 Beverage를 상속받고 있습니다.
코드를 살펴볼까요~
1 2 3 4 5 6 7 8 9 10 11 | public abstract class Beverage { protected string _description = "No Name"; public virtual string GetDescription() { return _description; } public abstract double Cost(); } | cs |
우선 Beverage 클래스입니다. 추상 클래스이며, 포함된 메서드로는 품명을 가져오는 GetDescription()과 가격을 가져오는 Cost()으로 구성됩니다.
다음은 추상 클래스인 CondimentDecorator 입니다. 부재료, 소스로 들어가는 데코레이터 클래스들의 추상 클래스이며
Beverage의 GetDescription()을 override하여 재정의합니다.
1 2 3 4 | public abstract class CondimentDecorator : Beverage { public abstract override string GetDescription(); } | cs |
다음은 데코레이터 클래스를 살펴보겠습니다..
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class Mocha : CondimentDecorator { private Beverage _beverage; public Mocha(Beverage _beverage) { this._beverage = _beverage; // 상위 클래스로 위임을 위한 초기화 } public override string GetDescription() { return _beverage.GetDescription() + ", 모카"; } public override double Cost() { return _beverage.Cost() + 0.20; } } | cs |
CondimentDecorator를 상속받고 있고 상위 클래스로 위임을 하기 위해서 초기화를 합니다.
CondimentDecorator에서 상속받은 GetDescription을 override하여 모카가 추가 됬다고 설명을 추가를 하기도 합니다.
Cost() 부분에서도 모카가 옵션으로 추가가 됬으므로 0.20불을 추가합니다.
다음은 이 데코레이터 클래스로부터 꾸밈을 받는 객체 클래스를 살펴보겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 | public class DarkRoast : Beverage { public DarkRoast() { _description = "DarkRoast"; } public override double Cost() { return 0.89; } } | cs |
보시는 것처럼 근본이 되는 Beverage 클래스를 상속받고 있고 제품명을 초기화하고 가격인 Cost()를 override하여 리턴합니다.
그럼 이제 호출부를 살펴볼까요?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private void InitData() { Beverage bev1 = new DarkRoast(); bev1 = new Mocha(new Soy(bev1)); label1.Text = string.Format(bev1.GetDescription() + " $" + bev1.Cost()); Beverage bev2 = new Espresso(); bev2 = new Mocha(new SteamMilk(bev2)); label2.Text = string.Format(bev2.GetDescription() + " $" + bev2.Cost()); Beverage bev3 = new HouseBlend(); bev3 = new SteamMilk(new Whip(bev3)); label3.Text = string.Format(bev3.GetDescription() + " $" + bev3.Cost()); } | cs |
저는 윈폼기반으로 작업을 했습니다.
우선 코드를 살펴보시면 bev1이라는 이름으로 Beverage 객체를 선언하면서 DarkRoast 객체를 생성했습니다.
그리고 순서대로 두유를 추가하고, 모카를 추가했습니다.
나머지 bev2, 3도 마찬가지입니다.
결과 화면은 다음과 같습니다.
데코레이터 클래스 호출 순서에 따라서 배열되는 것은 당연하겠죠?
위의 예제에서와 같이 기능의 추가(예제에서는 옵션 이름과, 가격을 추가했습니다.)할 때 유용하게 쓰이는 것이
데코레이터 패턴입니다.
적절히 사용할 때는 유용한 패턴이나 너무 많아지는 경우 코드가 복잡해지는 단점이 있다고 합니다.
'IT Engineering > 객체지향&디자인 패턴' 카테고리의 다른 글
[SOLID] 단일책임원칙 / SRP : Single Responsibility Priciple (0) | 2016.06.24 |
---|---|
Facade Pattern (파사드 패턴) (0) | 2016.06.17 |
[객체지향 개발] 캡슐화(Capsulation) (0) | 2016.06.16 |
Template Method Pattern (템플릿 메서드 패턴) (0) | 2016.06.14 |
Strategy Pattern (전략 패턴) (0) | 2016.06.14 |