https://codingnuri.com/seven-virtues-of-good-object/
위 포스팅을 읽고 final클래스를 상속 받을 수 없지만, 확장이 데코레이터 패턴이라는 방식으로 가능하다는 것을 알았다.
이건 어떤 방식일까?
새로운 구현체가 확장하고자 하는 클래스를 인스턴스 변수로 가지고, 이를 통해 기능을 확장할 수 있다.
예를 들어 아래 그림과 같이 기본 요금에 대해 추가 거리에 따라 요금을 다르게 계산하고 싶다면 basicFare을 확장하는 distanceOverFare는 변수로 가진 BasicFare의 caculate에 추가 작업을 거리에 따른 요금을 계산할 수 있다.
예를 들어,(현실적으로 없을 요구사항이지만) 블랙잭 카드게임에서 stay클래스를 확장해 이름이 3글자 이상이라면 배팅결과를 2배로 늘리는 Eventstay를 만들고자 하면, 아래와 같은 시도를 할 수 있다.
//decorator
public abstract class Decorator implements State {
protected final Finished target;
protected Decorator(Cards cards) {
this.target = new Stay(cards);
}
protected Result playDelegate(Hand dealer) { return target.play(dealer); }
}
//기존의 stay
public final class Stay extends Finished {
protected Stay(final Cards cards) {
super(cards);
}
@Override
public Result play(Hand dealer) {
Cards dealerCards = dealer.cards();
if (cards().isScoreOver(dealerCards)) {
return Result.WIN;
}
if (cards().isScoreUnder(dealerCards)) {
return Result.LOSE;
}
return Result.DRAW;
}
}
// 확장된 stay
public final class EventStay extends Decorator {
private final Finished stay;
private final Name name;
protected EventStay(final Cards cards, Name name) {
super(cards);
this.name = name
}
@Override
public Result play(Hand dealer) {
Result result = super.playDelegate(dealer);
if (name.size() >= 3) {
return Result.multiply(result, 2);
}
return result;
}
}
데코레이션 패턴이라는 이름이 붙었지만 사실 조합을 통해 기존 클래스를 확장하는 방식으로 생각하면 될 것 같다.
https://bugoverdose.github.io/development/decorator-pattern-implementation-and-limitations/