유니티/디자인패턴
[Unity] 유니티 C#) Decorator 패턴
새벽_글쓴이
2024. 12. 10. 10:25
반응형
데코레이터 패턴
객체에 동적으로 새로운 책임과 기능을 추가할 수 있게 해주는 구조적 디자인 패턴
기본구현방법
1. 기본 무기 인터페이스
public interface IWeapon
{
float GetDamage();
string GetDescription();
}
2.기본 무기 구현
public class BasicSword : IWeapon
{
public float GetDamage()
{
return 10f;
}
public string GetDescription()
{
return "기본 검";
}
}
3. 무기 데코레이터 기본 클래스
public abstract class WeaponDecorator : IWeapon
{
protected IWeapon weapon;
public WeaponDecorator(IWeapon weapon)
{
this.weapon = weapon;
}
public virtual float GetDamage()
{
return weapon.GetDamage();
}
public virtual string GetDescription()
{
return weapon.GetDescription();
}
}
4. 화염 강화 데코레이터
public class FireEnhancement : WeaponDecorator
{
public FireEnhancement(IWeapon weapon) : base(weapon) { }
public override float GetDamage()
{
return base.GetDamage() + 5f; // 추가 화염 데미지
}
public override string GetDescription()
{
return base.GetDescription() + " + 화염 강화";
}
}
5. 날카로움 강화 데코레이터
public class SharpnessEnhancement : WeaponDecorator
{
public SharpnessEnhancement(IWeapon weapon) : base(weapon) { }
public override float GetDamage()
{
return base.GetDamage() * 1.2f; // 20% 데미지 증가
}
public override string GetDescription()
{
return base.GetDescription() + " + 날카로움 강화";
}
}
사용 예시
// 플레이어 클래스
public class Player : MonoBehaviour
{
private IWeapon weapon;
void Start()
{
// 기본 무기 생성
weapon = new BasicSword();
Debug.Log($"기본 무기: {weapon.GetDescription()}, 데미지: {weapon.GetDamage()}");
// 화염 강화 추가
weapon = new FireEnhancement(weapon);
Debug.Log($"강화된 무기: {weapon.GetDescription()}, 데미지: {weapon.GetDamage()}");
// 날카로움 강화 추가
weapon = new SharpnessEnhancement(weapon);
Debug.Log($"최종 무기: {weapon.GetDescription()}, 데미지: {weapon.GetDamage()}");
}
}
핵심 개념
- 기존 객체의 기능을 동적으로 확장/수정할 수 있게 해주는 구조적 패턴
- 상속 대신 합성(Composition)을 사용하여 유연성 확보
- 각 데코레이터는 기본 객체와 동일한 인터페이스를 구현
- 여러 데코레이터를 조합하여 기능을 쌓아갈 수 있음
사용 목적
- 런타임에 객체의 기능을 동적으로 추가/변경해야 할 때
- 상속으로 처리하기에는 조합이 너무 많아질 때
- 기존 코드를 수정하지 않고 새로운 기능을 추가하고 싶을 때
- 객체의 책임과 기능을 분리하여 단일 책임 원칙을 지키고 싶을 때
사용 사례
- 무기/장비 강화 시스템
- 캐릭터 버프/디버프 시스템
- 스킬 조합 시스템
- UI 컴포넌트 확장
사용 사례 예시 코드
1. 무기/장비 강화 시스템
무기 시스템: 기본 무기에 강화 효과 추가
public interface IWeapon
{
float GetDamage();
string GetDescription();
}
public class BasicSword : IWeapon
{
public float GetDamage() => 10f;
public string GetDescription() => "기본 검";
}
public class EnhancementDecorator : IWeapon
{
protected IWeapon weapon;
public EnhancementDecorator(IWeapon weapon) => this.weapon = weapon;
public virtual float GetDamage() => weapon.GetDamage();
public virtual string GetDescription() => weapon.GetDescription();
}
public class FireEnhancement : EnhancementDecorator
{
public FireEnhancement(IWeapon weapon) : base(weapon) {}
public override float GetDamage() => base.GetDamage() + 5f;
public override string GetDescription() => base.GetDescription() + " + 화염 강화";
}
// 사용 예시
IWeapon sword = new BasicSword();
sword = new FireEnhancement(sword);
2.캐릭터 버프 / 디버프 시스템
버프 시스템: 캐릭터 기본 능력치에 버프 효과 적용
public interface ICharacterStats
{
float GetAttack();
float GetDefense();
}
public class BaseCharacter : ICharacterStats
{
public float GetAttack() => 10f;
public float GetDefense() => 5f;
}
public class BuffDecorator : ICharacterStats
{
protected ICharacterStats character;
public BuffDecorator(ICharacterStats character) => this.character = character;
public virtual float GetAttack() => character.GetAttack();
public virtual float GetDefense() => character.GetDefense();
}
public class StrengthBuff : BuffDecorator
{
public StrengthBuff(ICharacterStats character) : base(character) {}
public override float GetAttack() => base.GetAttack() * 1.5f;
}
// 사용 예시
ICharacterStats player = new BaseCharacter();
player = new StrengthBuff(player);
3. 스킬 조합 시스템
스킬 시스템: 기본 스킬에 추가 효과 조합
public interface ISkill
{
float GetDamage();
string GetEffect();
}
public class BaseFireball : ISkill
{
public float GetDamage() => 20f;
public string GetEffect() => "화염 데미지";
}
public class SkillDecorator : ISkill
{
protected ISkill skill;
public SkillDecorator(ISkill skill) => this.skill = skill;
public virtual float GetDamage() => skill.GetDamage();
public virtual string GetEffect() => skill.GetEffect();
}
public class IceEffect : SkillDecorator
{
public IceEffect(ISkill skill) : base(skill) {}
public override string GetEffect() => base.GetEffect() + " + 빙결 효과";
}
// 사용 예시
ISkill fireball = new BaseFireball();
fireball = new IceEffect(fireball); // 얼음 화염구
4. UI 컴포넌트 확장
UI 시스템: 기본 UI 요소에 시각 효과 추가
public interface IUIElement
{
void Render();
string GetStyle();
}
public class BasicButton : IUIElement
{
public void Render() => Debug.Log("기본 버튼 렌더링");
public string GetStyle() => "기본 스타일";
}
public class UIDecorator : IUIElement
{
protected IUIElement element;
public UIDecorator(IUIElement element) => this.element = element;
public virtual void Render() => element.Render();
public virtual string GetStyle() => element.GetStyle();
}
public class AnimationDecorator : UIDecorator
{
public AnimationDecorator(IUIElement element) : base(element) {}
public override void Render()
{
base.Render();
Debug.Log("애니메이션 효과 추가");
}
}
// 사용 예시
IUIElement button = new BasicButton();
button = new AnimationDecorator(button);
결론
장점
- 기능 확장이 유연하고 동적임
- 각 기능을 분리하여 관리 용이
- 기존 코드 수정 없이 새 기능 추가 가능
- 여러 기능을 조합하여 사용 가능
단점
- 데코레이터 클래스가 많아지면 복잡도 증가
- 순서에 따라 결과가 달라질 수 있음
- 작은 객체들이 많이 생성될 수 있음
데코레이터 패턴은 동적으로 기능 추가가 가능하고 기능의 조합이 자유롭다
또한, 코드 재사용성이 높고 확장이 용이하기에 유연하고 확장 가능한
시스템을 구축할 수 있을 것 같다
반응형