[읽기전에]
UML 다이어그램 : UML클래스 다이어그램 기본상식 http://hongjinhyeon.tistory.com/25
포스팅되는 디자인 패턴의 예는 스타크래프트를 기본으로 하였습니다 : 디자인 패턴을 시작하며 http://hongjinhyeon.tistory.com/24
<기본 정의 >
1. Adapter Pattern 정의
-객체에 추가적인 요건을 동적으로 첨가한다.
데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.
(Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending functionality. )
-어셈블리 타임이 아니라 런타임에 기능을 동적으로 추가가 가능하게 만들 수 있다.
2. UML Diagram
3. 사용용도 및 장점
-클래스의 기능들이 동적으로 변경될 소지가 있을때.
-클래스에 동적으로 추가하는 기능들이 앞으로 더 추가될 소지가 있을때 ( 기존기능에 추가로 새로운 기능이 추가가 될 소지가 있을때 )
-클래스에 기능들을 여러개로 조합이 될때 미리 정의해두면 너무 많은 클래스가 생성이 되므로, 즉시 즉시 생성이 가능하게 할때.
-클래스에 새로운 기능을 추가할때 보통 변수나 메소드 들이 추가가 된다. 그럴때마다 추상 클래스나 해당객체에 소스 변경이 있을 수
밖에 없다. 이것을 없앨 수가 있으며, 단순히 새로운 기능의 클래스만 추가되고 클라이언트 부분에서 기능만 추가만 해주면 된다.
4. 소스
using System; namespace DoFactory.GangOfFour.Decorator.Structural { /// <summary> /// MainApp startup class for Structural /// Decorator Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main() { // Create ConcreteComponent and two Decorators ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(); ConcreteDecoratorB d2 = new ConcreteDecoratorB(); // Link decorators d1.SetComponent(c); d2.SetComponent(d1); d2.Operation(); // Wait for user Console.ReadKey(); } } /// <summary> /// The 'Component' abstract class /// </summary> abstract class Component { public abstract void Operation(); } /// <summary> /// The 'ConcreteComponent' class /// </summary> class ConcreteComponent : Component { public override void Operation() { Console.WriteLine("ConcreteComponent.Operation()"); } } /// <summary> /// The 'Decorator' abstract class /// </summary> abstract class Decorator : Component { protected Component component; public void SetComponent(Component component) { this.component = component; } public override void Operation() { if (component != null) { component.Operation(); } } } /// <summary> /// The 'ConcreteDecoratorA' class /// </summary> class ConcreteDecoratorA : Decorator { public override void Operation() { base.Operation(); Console.WriteLine("ConcreteDecoratorA.Operation()"); } } /// <summary> /// The 'ConcreteDecoratorB' class /// </summary> class ConcreteDecoratorB : Decorator { public override void Operation() { base.Operation(); AddedBehavior(); Console.WriteLine("ConcreteDecoratorB.Operation()"); } void AddedBehavior() { } } }
5. 실행결과
ConcreteComponent.Operation()
ConcreteDecoratorA.Operation()
ConcreteDecoratorB.Operation()
< 실제 적용 >
1. UML Diagram
2. 사용용도 및 장점
-데코레이터 패턴이 스타크래프트에서 어떻게 적용되는지 고민을 많이했다. 생각보다 쓰이는 위치가 많지는 않은거 같다.
(좀 억지스러운 면도 있을 수 있겠지만 그냥 장식자를 설명할 꺼리로 생각해주면... ^^)
-테란 유닛중에 사이언스 배슬이라는 유닛은 아군에게 방어막(Defensive Matrix)를 걸어 줄 수가있다. 이것이 활성화된 유닛은
적의 공격을 받으면 방어막의 체력만큼 데미지를 일정기간동안 흡수가된다. 방어막의 공격력을 넘으면 본체의 체력이 줄어 들게
된다. 이런 경우에 사용이 가능하다.
-유닛에게 효과가 적용되는 기술이나 기능이 추가될때는, UnitDecorator를 상속받는 클래스를 생성해주고 신규 기술을 생성해주고
유닛에게 기술을 적용만 해주면 된다.
3. 소스
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Decorator { class Program { static void Main(string[] args) { // Create ConcreteComponent and two Decorators Marine marine = new Marine(); DefensiveMatrix defensiveMatrix= new DefensiveMatrix(); // Link decorators defensiveMatrix.SetComponent(marine); defensiveMatrix.UnderAttack(50); defensiveMatrix.UnderAttack(50); defensiveMatrix.UnderAttack(50); // Wait for user Console.ReadKey(); } /// <summary> /// 콤포넌트 클래스 /// </summary> abstract class Unit { public int health = 100; public abstract void UnderAttack(int _Damage); } /// <summary> /// ConcreteComponent 클래스 /// </summary> class Marine : Unit { public override void UnderAttack(int _Damage) { health -= _Damage; Console.WriteLine("남은 체력 : " + health.ToString() + ", 받은 데미지 : " + _Damage.ToString()); } } /// <summary> /// 데코레이터 클래스 /// </summary> abstract class UnitDecorator : Unit { protected Unit component; public void SetComponent(Unit component) { this.component = component; } public override void UnderAttack(int _Damage) { if (component != null) { component.UnderAttack(_Damage); } } } /// <summary> /// ConcreteDecorator 클래스 /// </summary> class DefensiveMatrix : UnitDecorator { private int addedHealth = 100; private int damage = 0; public override void UnderAttack(int _Damage) { CheckDefensiveMatrix(_Damage); base.UnderAttack(damage); } void CheckDefensiveMatrix(int _Damage) { int remainHealth=addedHealth-_Damage; //addedHealth -= _Damage; if (remainHealth >= 0) { //방어막이 데미지를 모두 흡수 했을때 addedHealth -= _Damage; Console.WriteLine("보호막으로 데미지 " + _Damage.ToString() + "모두 흡수 ,남은 보호막 : " + remainHealth.ToString()); damage = 0; } else { //방어막이 모두달았을때 if (addedHealth == 0) { //기존의 방어막이 없었을때 Console.WriteLine("보호막으로 흡수 못함, 남은 보호막 : 0"); damage = _Damage; } else { //기존의 방어막이 있는데 다 소멸되었을대 Console.WriteLine("보호막으로 데미지 " + (_Damage - addedHealth).ToString() + "만 흡수, , 남은 보호막 : 0"); damage = _Damage - addedHealth; addedHealth = 0; } } } } } }
4. 실행결과
5. 피드백
-데코레이터 패턴을 설명하는데 예를 들을때 보통 커피전문점을 든다. 커피종류에 토핑을 머로 하느냐에 따라서 다양한 커피종류와
가격이 형성되므로 데코레이터 패턴을 적용하기에 알맞다. (Head First Desing Patterns에 잘 나와있다)
-데코레이터 패턴은 기존 클래스에 새로운 기능이 많이 추가될 수가 있고, 종류가 다양할 때만 사용하는게 좋을거 같다. 너무 적은량이면
그냥 고정적으로 하는것이 더 효율적으로 보인다. (큰 프로젝트가 아니라면 더더욱...)
[참조]
-http://www.dofactory.com
'프로젝트 설계 > 디자인 패턴' 카테고리의 다른 글
7. Observer Pattern ( 옵져버 패턴 C# ) (3) | 2012.09.05 |
---|---|
6. Facade Pattern (퍼사드 패턴 C# ) (2) | 2012.09.04 |
4. Adapter Pattern ( 어댑터 / 적응자 패턴 C# ) (2) | 2012.08.28 |
3. Abstract Factory Pattern ( 추상 팩토리 패턴 C# ) (2) | 2012.08.26 |
2. Factory Method Pattern ( 팩토리 매소드 패턴 C# ) (14) | 2012.08.22 |