참치김밥은 최고의 한식이다

[디자인 패턴] 데커레이터로 무기 시스템 구현하기 본문

[디자인 패턴] 데커레이터로 무기 시스템 구현하기

l__j__h 2024. 2. 21. 16:59

해당 문서는 "유니티로 배우는 게임 디자인 패턴" 책을 읽고 작성하였습니다.

 

데커레이터(Decorator)는 말 그대로, 꾸며주는 역할을 담당한다고 보면 된다.

보통 꾸밀 때, 장식을 여기저기 "덧붙이지" 않는가?!

이런 방식으로 무기의 슬롯 시스템을 편리하게 개발할 수 있다.

 

데커레이터는 기존 객체를 변경하지 않고 새로운 기능을 추가할 수 있는 패턴이다. 이 패턴을 사용하면, 객체에 새로운 행동을 쉽게 부여하거나 분리할 수 있다!

 

긴 말 말고 어떤 클래스가 있는지부터 보자

1. 무기

2. 무기에 붙일 부착물

3. 무기와 부착물을 저장하고, 무기의 성능 + 부착물의 성능을 리턴할 Decorator

4. 1번과 3번의 형식을 통일시켜줄 Interface

일단 이렇게 4개만 있으면 된다!! (사실 한 개 더 있는데 그건 일단 포스팅 후반에 설명)

 

그럼 코드를 보자

 

1. 무기 클래스

public class Weapon : IWeapon
{
	public float Range {
    	get { return _config.Range; }
    }
    
    public float Rate {
    	get { return _config.Rate; }
    }
    
    public float Cooldown {
    	get { return _config.Cooldown; }
    }
    
    public float Strength {
    	get { return _config.Strength; }
    }
    
    private readonly WeaponConfig _config;
    
    public Weapon(WeaponConfig weaponConfig){
    	_config = weaponConfig;
    }
}

 

Weapon 클래스는 어떤 동작도 구현하지 않는다. 구성할 수 있는 무기의 속성을 나타낼 뿐이다. 

 

2. 무기에 붙일 부착물 클래스

[CreateAssetMenu(filename = "NewWeaponAttachment", menuName = "Weapon/Attachment", order = 1)]
public class WeaponAttachment : ScriptableObject, IWeapon
{
	[Range(0, 50)]
    [SerializeField]
    public float rate;
    
    [Range(0, 50)]
    [SerializeField]
    float range;
    
    [Range(0, 50)]
    [SerializeField]
    public float strength;
    
    [Range(0, 50)]
    [SerializeField]
    public float cooldown;
    
    public string attachmentName;
    public GameObject attachmentPrefab;
    public string attachmentDescription;
    
    public float Rate {
    	get { return rate; }
    }
    
    public float Range{
    	get { return range; }
    }
    
    public float Strength {
    	get { return strength; }
    }
    
    public float Cooldown {
    	get { return cooldown; }
    }
}

WeaponAttachmenet가 IWeapon 인터페이스를 구현한다는 점에 유의하자. 같은 인터페이스를 공유함으로써, WeaponDecorator 클래스는 Weapon 클래스와 일관성을 유지한다.

 

3. 무기와 부착물을 저장하고, 무기의 성능 + 부착물의 성능을 리턴할 Decorator 클래스

public class WeaponDecorator : IWeapon {
	private readonly IWeapon _decoratedWeapon;
    private readonly WeaponAttachment _attachment;
    
    public WeaponDecorator(IWeapon weapon, WeaponAttachment attachment){
        _decoratedWeapon = weapon;
        _attachment = attachment;
    }
    
    public float Rate {
    	get { return _decoratedWeapon.Rate + _attachment.Rate; }
    }
    
    public float Range {
    	get { return _decoratedWeapon.Range + _attachment.Range; }
    }
    
    public float Strength {
    	get { return _decoratedWeapon.Strength + _attachment.Strength; }
    }
    
    public float Cooldown {
    	get { return _decoratedWeapon.Cooldown + _attachment.Cooldown; }
    }
}

이 WeaponDecorate 클래스는 무기의 속성을 절대 수정하지 않는다.

단지, 무기(IWeapon)의 기존 속성에 부착물(Attachment)의 속성을 더하여 리턴해줄 뿐이다.

즉, 무기에 부착물을 Decorate하여, 무기의 슬롯 or 업그레이드 시스템을 만들어주는 것이다.

 

또, WeaponDecorate는 Weapon과 마찬가지로 IWeapon 인터페이스를 상속받는다.

즉, 위 코드에서 _decoratedWeapon가 IWeapon 인터페이스이기 때문에,

_decoratedWeapon에 WeaponDecorator를 넣어, 부착물을 2번 이상 계속해서 붙일 수 있다!!!

(사실상 여기까지만 봐도 Decorator 패턴 설명은 끝이다.)

 

4. Weapon 클래스와 WeaponDecorator 클래스의 형식을 통일시켜줄 Interface

public interface IWeapon {
	float Range { get; }
    float Rate { get; }
    float Strength { get; }
    float Cooldown { get; }
}

Weapon 클래스와 WeaponDecorator 클래스 간의 공통된 인터페이스를 구현한다.

 

 

+) Weapon 클래스의 WeaponConfig ??

WeaponConfig는 데코레이터 패턴과는 큰 관련이 없는 것 같아 이렇게 아래에 빼두었다.

WeaponConfig는 Weapon 객체의 다양한 구성을 만들 수 있게 해주는 ScriptableObject 이다.

[CreateAssetMenu(filename = "NewWeaponConfig", menuName = "Weapon/Config", order = 1)]
public class WeaponConfig : ScriptableObject, IWeapon
{
	[Range(0, 50)]
    [SerializeField]
    public float rate;
    
    [Range(0, 50)]
    [SerializeField]
    float range;
    
    [Range(0, 50)]
    [SerializeField]
    public float strength;
    
    [Range(0, 50)]
    [SerializeField]
    public float cooldown;
    
    public string weaponName;
    public GameObject weaponPrefab;
    public string weaponDescription;
    
    public float Rate {
    	get { return rate; }
    }
    
    public float Range{
    	get { return range; }
    }
    
    public float Strength {
    	get { return strength; }
    }
    
    public float Cooldown {
    	get { return cooldown; }
    }
}

 

 

흥미롭다.

728x90

'' 카테고리의 다른 글

[디자인 패턴] 방문자 패턴  (4) 2023.11.22