동적으로 객체에 책임을 추가할수 있도록 한다. 즉, 객체의 결합을 통해 기능을 동적으로 유연하게 확장 할 수 있게 해주는 패턴이다.
보통 RPG게임에서 스킬의 레벨이 오르면 스킬트리와 같은 기능을 통해 스킬을 자유롭게 확장이 가능하다.
1. 기본 캐릭터의 스킬은 다음과 같다.
public interface Character {
String getSkills();
}
public class BasicCharacter implements Character {
@Override
public String getSkills() {
return "Basic attack";
}
}
2. 불속성(Fire)스킬과 얼음속성(Ice)스킬로 확장한다면 다음과 같이 만들 수 있다.
public class FireMage implements Character {
@Override
public String getSkills() {
return "Basic attack, Fireball";
}
}
public class IceMage implements Character {
@Override
public String getSkills() {
return "Basic attack, Ice shard";
}
}
3. 이후에 스킬이 더 확장되어서 연쇄(Explosive)스킬로 확장된다면 다음과 같은 스킬을 추가해야 한다.
public class ExplosiveFireMage implements Character {
@Override
public String getSkills() {
return "Basic attack, Fireball, Chain Explosion";
}
}
public class ExplosiveIceMage implements Character {
@Override
public String getSkills() {
return "Basic attack, Ice shard, Chain Explosion";
}
}
위 상황은 스킬을 확장하는 과정의 모든 경우에 대한 구현이 필요한 상황이다. 이런 경우는 구현해야 할 코드의 양이 매우 많아지고 스킬의 추가, 변경, 삭제가 어려워진다.
스킬의 확장을 하나의 객체로 만들어 객체의 결합을 동적으로 바꾸게 하자
1. Character
public interface Character {
String getSkills();
}
public class BasicCharacter implements Character {
@Override
public String getSkills() {
return "Basic attack";
}
}
BasicCharacter는 ConcreteComponent에 해당하는 기본 기능을 구현한 클래스이다.
2. SkillDecorator
public abstract class SkillDecorator implements Character {
protected Character character;
public SkillDecorator(Character character) {
this.character = character;
}
@Override
public String getSkills() {
return character.getSkills();
}
}
Decorator에 해당하는 클래스로 Component(Character)의 operation을 실행하도록 정의된 추상클래스이다.
3. Fireball, IceShard, ChainExplosion Decorator
public class FireballDecorator extends SkillDecorator {
public FireballDecorator(Character character) {
super(character);
}
@Override
public String getSkills() {
return super.getSkills() + ", Fireball";
}
}
public class IceShardDecorator extends SkillDecorator {
public IceShardDecorator(Character character) {
super(character);
}
@Override
public String getSkills() {
return super.getSkills() + ", Ice shard";
}
}
public class ChainExplosionDecorator extends SkillDecorator {
public ChainExplosionDecorator(Character character) {
super(character);
}
@Override
public String getSkills() {
return super.getSkills() + ", Chain Explosion";
}
}
ConcreteDecorator에 해당하는 클래스로 각각 불속성, 얼음속성, 연쇄에 대한 기능을 추가하는 Decorator이다. ConcreteDecorator는 다음과 같은 단계로 동작한다.
1. 생성자에서 상위클래스의 생성자로 상위 Component를 설정한다.
2. 상위 Component의 operation(getSkills)를 먼저 실행 한 후 해당 Decorator에 수행할 연산을 실행한다.
만약 불속성 연쇄 스킬
을 만들고자 할 때 Client는 어떻게 Character를 생성해야 할까?
결국, 기능을 수행하는 최종 객체는 ConcreteComponent에 해당하는 BasicCharacter이다. 즉, 최상위 클래스는 BasicCharacter
이고 아래에 FireballDecorator
와 ChainExplosionDecorator
있는 구조여야 한다.
Character fireExplosionCh = new ChainExplosionDecorator(new FireballDecorator(new BasicCharacter()));
위와 같이 하면 최상위 클래스는 BasicCharacter
이 생성되고, 이후에 FireballDecorator
와 ChainExplosionDecorator
가 순서대로 생성되어 밑에 위치하는 구조가 된다.