2022. 3. 8. 00:00ㆍCSharp/Design Pattern
객체들의 관계를 트리 구조로 구성하여 부분-전체 계층을 표현하는 패턴
사용자가 단일 객체와 복합 객체 모두 동일하게 다루도록 한다.
위와 같이 특정 제품들을 모아놓은 box 의 총 가격을 계산한다고 가정하자
각각을 다 풀어서 계산 할 수 있지만 프로그램상에서는 다음과 같은 과정이 필요하다.
- 각 class 들의 특성(사용법) 및 method 를 알아야 한다.
- 각 class 들의 가격을 담당하는 특성 및 interface 를 client 가 알고 있어야한다.
- 각 class 들의 가격은 최종 가격일 수도 있고 client 에서 다시 계산해줘야 할 수도 있다.
위와 같은 과정을 거쳐야 해당 제품의 가격을 알 수 있다. 이건 너무 복잡하고 힘든 과정이다.
총 가격을 계산하는 방법을 선언하는 공통 인터페이스를 통해 client 에 계산을 위임한다면 훨씬 편리 할 것이다.
이 과정을 그림으로 표현 한다면 아래와 같다.
class diagram
Component
추상화된 interface , "Leaf" 와 "Composite" 클래스의 공통 인터페이스
Leaf
추상화된 인터페이스(Component)를 구현하는 단일객체.
Composite
추상화된 인터페이스(Component)를 구현하는 복합객체
다른 복합객체 및 단일객체 들을 자식요소로 포함함
이러한 자식요소들을 관리하기 위한 메소드(add, remove, getChildren ...)를 구현
작성된 메소드는 자식에게 위임
Composite.Method() => Leaf.Method()
이제 전사, 도적, 암살자의 공격력을 Composite 을 활용하여 계산해 보자.
Leaf 에 해당하는 각 무기들
public interface IWeapon
{
int AttackPower();
}
public class BastardSword : IWeapon
{
public int AttackPower() => 7;
}
public class Dagger : IWeapon
{
public int AttackPower() => 5;
}
public class DoubleSword : IWeapon
{
public int AttackPower() => 20;
}
Composite 에 해당 하는 무기pack
public interface ICompositeWeapon:IWeapon
{
void Add(IWeapon weapon);
void Remove(IWeapon weapon);
}
public class CompositeWeapon: ICompositeWeapon
{
private List<IWeapon> _weapons = new List<IWeapon>();
public void Add(IWeapon weapon) => _weapons.Add(weapon);
public void Remove(IWeapon weapon) => _weapons.Remove(weapon);
public int AttackPower() => _weapons.Sum(weapon => weapon.AttackPower());
}
Sum 을 이용하여 각 무기들(leaf)의 공격력을 더한다.
AttackPower 를 계산 하려는 Unit
public abstract class Unit
{
protected ICompositeWeapon _weapon;
public Unit(ICompositeWeapon weapon) => _weapon = weapon;
public abstract void Attack();
}
public class Warrior : Unit
{
public Warrior(ICompositeWeapon weapon) : base(weapon) { }
public override void Attack() => Console.WriteLine($"전사가 공격하여 {_weapon.AttackPower()} 데미지를 입혔습니다.");
}
public class Rogue : Unit
{
public Rogue(ICompositeWeapon weapon) : base(weapon) { }
public override void Attack() => Console.WriteLine($"도적이 공격하여 {_weapon.AttackPower()} 데미지를 입혔습니다.");
}
public class Assassin : Unit
{
public Assassin(ICompositeWeapon weapon) : base(weapon) { }
public override void Attack() => Console.WriteLine($"암살자가 공격하여 {_weapon.AttackPower()} 데미지를 입혔습니다.");
}
사용법
ICompositeWeapon weapon = new CompositeWeapon();
weapon.Add(new BastardSword());
Unit unit = new Warrior(weapon);
unit.Attack();
weapon = new CompositeWeapon();
weapon.Add(new Dagger());
weapon.Add(new DoubleSword());
unit = new Rogue(weapon);
unit.Attack();
unit = new Assassin(weapon);
weapon.Add(new Dagger());
weapon.Add(new Dagger());
weapon.Add(new DoubleSword());
unit.Attack();
// output
전사가 공격하여 7 데미지를 입혔습니다.
도적이 공격하여 25 데미지를 입혔습니다.
암살자가 공격하여 55 데미지를 입혔습니다.
관련영상
'CSharp > Design Pattern' 카테고리의 다른 글
Flyweight (0) | 2022.03.11 |
---|---|
Facade (0) | 2022.03.10 |
Decorator (0) | 2022.03.09 |
Bridge (0) | 2022.03.07 |
Adapter (Structural Pattern) (0) | 2022.02.28 |