데코레이터 패턴을 이용하면 어떤 오브젝트에 정적으로 또는 동적으로
책임(기능)을 추가할 수 있다. -Baeldung-
참고한 링크: https://www.baeldung.com/java-decorator-pattern
데코레이터 패턴은 말 그대로 어떤 오브젝트에 대해 데코레이션 하듯이
기능을 추가해주는 것이다.
A라는 인터페이스가 있고 B, C 라는 구현체가 있다면
B가 핵심 기능을 담당하고 C가 부가 기능을 담당한다.
C는 B를 주입받아 B에게 핵심 기능을 위임하고
자신은 부가 기능에 대해 처리한다.
말이 어려우니 그림으로 보자.
예를 들어 A 가 DAO인터페이스이고 B가 데이터베이스의 CRUD 에 대한 책임을 갖고 있다면 C는 트랜잭션에 대한 책임만 담당할 수 있다.
C 는 자신의 트랜잭션 메서드들 사이에 B 의 메서드를 호출하며 두개의 책임을 하나로 묶을 수 있다.
Baeldung이 제공하는 예제를 이용해보자.
아까 그림보다 조금더 복잡하긴 한데, 부가기능을 담는 클래스에 구현체가 여러개 생겼을 뿐이다.
ChristmasTreeImpl 의 decorate() 이 핵심 기능이고
TreeDecorator 의 구현체들의 메서드가 부가 기능이다.
꾸미자 방울로, 꾸미자 꽃으로 이런식으로 부가 기능을 적용할 것이다.
public interface ChristmasTree {
//인터페이스이기 때문에 public abstract 생략
void decorate();
}
//핵심 기능을 담당하는 클래스
public class ChristmasTreeImpl implements ChristmasTree {
@Override
public void decorate() {
System.out.println("꾸미자 ");
}
}
//부가 기능을 담는 클래스
public class TreeDecorator implements ChristmasTree{
//핵심 기능을 담는 오브젝트를 주입받는다.
private ChristmasTree tree;
public TreeDecorator(ChristmasTree tree) {
this.tree = tree;
}
@Override
public void decorate() {
tree.decorate();
}
}
public class Garland extends TreeDecorator{
public Garland(ChristmasTree tree) {
super(tree);
}
@Override
public void decorate() {
super.decorate();
decorateWithTreeDecorator();
}
private void decorateWithTreeDecorator(){
System.out.println("꽃잎으로");
}
}
구현 클래스 나머지 3개는 거의 같다.
//테스트 클래스(클라이언트)
public class DecoratorTest {
@Test
public void decoratorPatternTest(){
// 부가기능 오브젝트에 핵심 기능 오브젝트를 주입해준다.
//런타임시 동적으로 오브젝트의 관계가 형성돼 부가기능이 적용된다.
ChristmasTree christmasTree = new Garland(new ChristmasTreeImpl());
christmasTree.decorate();
//결과:
//꾸미자
//꽃잎으로
ChristmasTree christmasTree1 = new TreeTopper(new ChristmasTreeImpl());
christmasTree1.decorate();
//결과:
//꾸미자
//트리 꼭대기 장식으로
}
}
데코레이터 패턴은 Spring AOP를 이해하려면 알아야 한다. 확실히 알고 넘어가는게 좋을 것 같다.