home

데코레이터 패턴

  • 데코레이터 패턴(Decorator Pattern)은 객체에 추가적인 기능을 동적으로 첨가할 수 있도록 해주는 구조적 디자인 패턴
  • 대상 객체에 확장, 변경이 필요할 때 객체의 결합을 통해 새로운 기능을 추가 가능

alt text

  • Component: 원복 객체와 장식 객체를 모두 묶는다.
  • ConcreteComponent: 데코레이팅 할 객체
  • Decorator: 추상화된 데코레이터 객체, 래핑된 객체를 참조하는 필드가 있다. 또한 컴포넌트 인터페이스의 구현 메소드를 갖는다.
  • ConcreteDecorator: 데코레이터 구현체, 부모의 컴포넌트를 호출하고, 부가적인 추가 로직이 있다.

python 예제 코드

from abc import ABC, abstractmethod

class Character(ABC):
    @abstractmethod
    def attack(self):
        pass

    @abstractmethod
    def magic_attack(self):
        pass

    @abstractmethod
    def get_description(self):
        pass

class Warrior(Character):
    def attack(self):
        return 10
    
    def magic_attack(self):
        return 0
    
    def get_description(self):
        return "물리 공격력이 강한 전사이다."

class Mage(Character):
    def attack(self):
        return 3
    
    def magic_attack(self):
        return 10
    
    def get_description(self):
        return "마법 공격력이 강한 마법사이다."
    
class CharacterDecorator(Character, ABC):
    def __init__(self, character):
        self._character = character

    @abstractmethod
    def attack(self):
        pass

    @abstractmethod
    def magic_attack(self):
        pass

    @abstractmethod
    def get_description(self):
        pass

class PowerStrikeDecorator(CharacterDecorator):
    def attack(self):
        return self._character.attack() + 15
    
    def magic_attack(self):
        return self._character.magic_attack()
    
    def get_description(self):
        return f"파워스트라이크 스킬을 가진 {self._character.get_description()}"
    
class EngergyBoltDecorator(CharacterDecorator):
    def attack(self):
        return self._character.attack()
    
    def magic_attack(self):
        return self._character.magic_attack() + 15
    
    def get_description(self):
        return f"에너지볼트 스킬을 가진 {self._character.get_description()}"
    
class FireChargeDecorator(CharacterDecorator):
    def attack(self):
        return self._character.attack()
    
    def magic_attack(self):
        return self._character.magic_attack() + 5
    
    def get_description(self):
        return f"파이어차지를 가진 {self._character.get_description()}"
    
    def set_elemental_attack(self):
        return "Fire"
  • 데코레이터 패턴을 가장 잘 표현할 수 있을 것 같은 예시를 만들었다.
  • RPG 게임에는 전사와 마법사 직업군이 존재하고, 각각에 맞는 스킬을 배울 수 있다.
  • 전사는 물리 공격력이 강하고, 마법사는 마법 공격력이 강하다.
  • 그리고, 직업군에 맞는 공격을 할 것이기에, 그에 맞는 스킬을 배워야 한다. 정석적인 스킬트리는 다음과 같다.
if __name__ == "__main__":
    # 기본 전사 캐릭터 생성
    warrior = Warrior()
    print(f"{warrior.get_description()} 공격력: {warrior.attack()}, 마법 공격력: {warrior.magic_attack()}")

    # 파워 스트라이크가 추가된 전사
    power_strike_warrior = PowerStrikeDecorator(warrior)
    print(f"{power_strike_warrior.get_description()} 공격력: {power_strike_warrior.attack()}, 마법 공격력: {power_strike_warrior.magic_attack()}")

    # 기본 마법사 캐릭터 생성
    mage = Mage()
    print(f"{mage.get_description()} 공격력: {mage.attack()}, 마법 공격력: {mage.magic_attack()}")

    # 에너지 볼트가 추가된 마법사
    energy_bolt_mage = EngergyBoltDecorator(mage)
    print(f"{energy_bolt_mage.get_description()} 공격력: {energy_bolt_mage.attack()}, 마법 공격력: {energy_bolt_mage.magic_attack()}")
  • 물리 공격력이 강한 전사는 물리 공격력이 강해진 상태로 공격하는 파워스트라이크, 마법사는 마법 공격력이 강해진 상태로 공격하는 에너지 볼트를 배웠다.
물리 공격력이 강한 전사이다. 공격력: 10, 마법 공격력: 0
파워스트라이크 스킬을 가진 물리 공격력이 강한 전사이다. 공격력: 25, 마법 공격력: 0

마법 공격력이 강한 마법사이다. 공격력: 3, 마법 공격력: 10
에너지볼트 스킬을 가진 마법 공격력이 강한 마법사이다. 공격력: 3, 마법 공격력: 25
  • 하지만, 어느 게임이든 정상적인 육성을 하기보다는 자신만의 스킬 트리를 만들어내는 괴짜들이 존재한다.

alt text

출처

alt text

출처

  • 이렇게 어떤 마법사는 물리적으로 공격을 하고, 에너지 볼트도 사용하는 하이브리드 육성법으로 캐릭터를 키웠다.

if __name__ == "__main__":
    # 파워 스트라이크가 추가된 마법사
    fire_charge_mage = PowerStrikeDecorator(energy_bolt_mage)
    print(f"{fire_charge_mage.get_description()} 공격력: {fire_charge_mage.attack()}, 마법 공격력: {fire_charge_mage.magic_attack()}")
파워스트라이크 스킬을 가진 에너지볼트 스킬을 가진 마법 공격력이 강한 마법사이다. 공격력: 18, 마법 공격력: 25
  • 또한, 마법 속성을 부여하여, 마법 추가 데미지를 주는 전사도 존재한다.
    # 파이어 차지가 추가된 전사
    fire_charge_warrior = FireChargeDecorator(power_strike_warrior)
    print(f"{fire_charge_warrior.get_description()} 공격력: {fire_charge_warrior.attack()}, 마법 공격력: {fire_charge_warrior.magic_attack()}")

파이어차지를 가진 파워스트라이크 스킬을 가진 물리 공격력이 강한 전사이다. 공격력: 25, 마법 공격력: 5, 속성: Fire

TradeOff

  • 장점
    • 단일 책임의 원칙, 개방 폐쇄의 원칙, 의존 역전 원칙을 잘 준수할 수 있다.
    • 서브 클래스를 만들어서 인스턴스화 하는 것 보다 유연한게 기능을 확장시킬 수 있다.
    • 데코레이터로 매핑해서 여러 동작을 결합 가능
  • 단점
    • 생성자 코드가 예쁘지 않다.
    • 데코레이팅 순서에 따라서 순서가 달라지기에, 순서에 영향을 많이 받는다