Unity에서 데코레이터 패턴 (Decorator Pattern) 활용하기 (1)

2025. 2. 9. 12:28유니티 unity/디자인패턴

게임 개발에서는 개별 객체의 기능을 동적으로 확장하거나 변경할 필요가 자주 발생합니다. 데코레이터 패턴은 기존 클래스를 수정하지 않고도 객체에 추가 기능을 부여할 수 있는 강력한 디자인 패턴입니다. 본 글에서는 데코레이터 패턴의 개념과 장점을 소개하고, Unity 환경에서 이를 적용하는 방법과 실제 응용 사례에 대해 상세히 설명합니다.


데코레이터 패턴이란?

데코레이터 패턴은 객체의 핵심 기능을 보존하면서, 추가적인 책임이나 행동을 동적으로 부여할 수 있도록 객체를 감싸는(랩핑하는) 구조적 디자인 패턴입니다.
즉, 기본 기능을 제공하는 객체(컴포넌트)를 그대로 유지한 채, 외부에서 추가 기능을 덧붙이는 별도의 데코레이터 클래스를 사용합니다. 이 방식은 상속을 통한 기능 확장이 아닌, 객체 합성을 통해 기능을 확장하므로, 코드의 유연성과 재사용성이 크게 향상됩니다.


데코레이터 패턴의 장점

  • 동적 기능 확장:
    객체의 기능을 실행 중에 동적으로 확장할 수 있으므로, 게임 플레이 도중 상황에 맞춰 추가 효과(예: 특수 공격 효과, 버프/디버프 적용 등)를 적용할 수 있습니다.
  • 유연한 코드 구조:
    상속이 아닌 객체 합성을 사용하므로, 기존 클래스를 수정하지 않고도 새로운 기능을 추가할 수 있습니다. 이를 통해 코드의 결합도를 낮추고 유지보수성을 높일 수 있습니다.
  • 재사용성 및 모듈화:
    데코레이터는 각 기능을 별도의 클래스에 캡슐화하여, 다른 객체에도 동일한 데코레이터를 적용할 수 있으므로, 코드의 재사용성이 높아집니다.
  • 조합의 자유:
    여러 데코레이터를 중첩하여 사용할 수 있으므로, 다양한 효과나 기능을 자유롭게 조합하여 적용할 수 있습니다.

Unity에서 데코레이터 패턴 적용 예제

이번 예제에서는 플레이어의 공격 기능에 추가 효과(예: 불 속성 공격, 얼음 속성 공격)를 동적으로 부여하는 예제를 통해 데코레이터 패턴을 구현합니다.

1. 기본 공격 인터페이스와 클래스 정의

먼저, 공격 기능을 정의하는 인터페이스와 기본 공격 클래스를 작성합니다.

 

 

// IAttack.cs
public interface IAttack
{
    void Execute();
}

 

using UnityEngine;

// BasicAttack.cs: 기본 공격 클래스입니다.
public class BasicAttack : IAttack
{
    public void Execute()
    {
        Debug.Log("기본 공격을 실행합니다.");
    }
}

 

2. 데코레이터 기본 클래스 구현

데코레이터는 IAttack 인터페이스를 구현하며, 내부에 IAttack 객체를 보유하여 기본 공격에 추가 기능을 덧붙입니다.

 

using UnityEngine;

// AttackDecorator.cs: 데코레이터 기본 클래스입니다.
public abstract class AttackDecorator : IAttack
{
    protected IAttack baseAttack;

    public AttackDecorator(IAttack attack)
    {
        baseAttack = attack;
    }

    public virtual void Execute()
    {
        baseAttack.Execute();
    }
}

3. 구체적인 데코레이터 클래스 구현

다음은 불 속성과 얼음 속성을 추가하는 구체적인 데코레이터 클래스를 구현합니다.

 

using UnityEngine;

// FireAttackDecorator.cs: 불 속성 효과를 추가합니다.
public class FireAttackDecorator : AttackDecorator
{
    public FireAttackDecorator(IAttack attack) : base(attack) { }

    public override void Execute()
    {
        base.Execute();
        Debug.Log("불 속성 효과를 추가합니다!");
        // 추가적인 불 효과 로직(예: 화염 파티클, 데미지 오버타임 적용 등)을 구현할 수 있습니다.
    }
}

 

using UnityEngine;

// IceAttackDecorator.cs: 얼음 속성 효과를 추가합니다.
public class IceAttackDecorator : AttackDecorator
{
    public IceAttackDecorator(IAttack attack) : base(attack) { }

    public override void Execute()
    {
        base.Execute();
        Debug.Log("얼음 속성 효과를 추가합니다!");
        // 추가적인 얼음 효과 로직(예: 이동 속도 감소, 얼음 파티클 효과 등)을 구현할 수 있습니다.
    }
}

 

4. 데코레이터 패턴 활용 예제 실행

MonoBehaviour 스크립트를 통해 데코레이터를 적용하여 공격 기능을 확장하는 예제를 작성합니다.

using UnityEngine;

public class DecoratorPatternTest : MonoBehaviour
{
    void Start()
    {
        // 기본 공격 객체 생성
        IAttack attack = new BasicAttack();
        
        // 데코레이터를 중첩하여 불 속성과 얼음 속성 효과를 추가합니다.
        attack = new FireAttackDecorator(attack);
        attack = new IceAttackDecorator(attack);

        // 최종 공격 실행: 기본 공격, 불 효과, 얼음 효과가 순서대로 적용됩니다.
        attack.Execute();
    }
}

 

실행 결과 예시:

---
 
기본 공격을 실행합니다.
불 속성 효과를 추가합니다!
얼음 속성 효과를 추가합니다!
 
---
 

이 예제에서는 데코레이터를 중첩하여 기본 공격에 두 가지 속성 효과를 추가하였습니다. 이처럼 데코레이터 패턴은 여러 기능을 유연하게 조합할 수 있게 하며, 필요에 따라 새로운 데코레이터를 추가하여 기능을 확장할 수 있습니다.

 

데코레이터 패턴은 여러 데코레이터를 조합할 수 있으므로, 상황에 따라 다양한 효과를 동시에 적용할 수 있습니다. 예를 들어, 공격에 추가적으로 치명타 효과, 흡혈 효과 등을 별도의 데코레이터로 구현할 수 있으며, 이를 조합하여 복합적인 공격 효과를 구성할 수 있습니다.

 

데코레이터 패턴을 사용할 때는 각 데코레이터가 래핑하는 객체를 추가로 호출하게 되므로, 호출 스택이 깊어질 수 있습니다. 게임의 실시간 처리 성능에 영향을 미칠 수 있으므로, 각 데코레이터의 연산 비용을 고려하여 적절한 수준에서 사용해야 합니다.

 

데코레이터 패턴은 전략 패턴, 상태 패턴 등 다른 디자인 패턴과 함께 사용되어 더욱 유연한 구조를 만들 수 있습니다. 예를 들어, 캐릭터의 공격 전략을 변경할 때, 기본 공격 객체를 데코레이터로 감싸 여러 효과를 적용한 후, 전략 패턴을 통해 공격 방식 자체를 동적으로 변경할 수 있습니다.