스프링/스프링 핵심 원리 - 고급편

30. 데코레이터 패턴

sdafdq 2024. 1. 19. 15:42
public interface Component {
    String operation();
}

인터페이스

 

@Slf4j
public class RealComponent implements Component{
    @Override
    public String operation() {
        log.info("RealComponent 실행");
        return "data";
    }
}

실제 서버에서 동작할 로직

 

@Slf4j
public class MessageDecorator implements Component{
    private Component component;

    public MessageDecorator(Component component) {
        this.component = component;
    }

    @Override
    public String operation() {
        log.info("MessageDecorator 실행");
        String result = component.operation();
        String decoResult = "*****" + result + "*****";
        log.info("MessageDecorator 꾸미기 적용 전={}, 적용 후={}", result, decoResult);
        return decoResult;
    }
}

이게 데코레이터 패턴의 데코레이터.

 

실제 서버에서 받은 문자형 데이터를 꾸며준다.

 

@Slf4j
public class DecoratorPatternClient {
    private Component component;

    public DecoratorPatternClient(Component component){
        this.component = component;
    }

    public void execute(){
        String result = component.operation();
        log.info("result={}",result);
    }
}

클라이언트 입장에서는 그냥 인터페이스의 operation을 실행한다.

 

@Test
void decorator1(){
    Component realComponent = new RealComponent();
    Component messageDecorator = new MessageDecorator(realComponent);
    DecoratorPatternClient client = new DecoratorPatternClient(messageDecorator);

    client.execute();
}

이렇게 실행.

 

 

앞서 이야기 했듯, 프록시 체인이 가능한데,

 

그냥 프록시가 프록시를 호출하고, 또 그 프록시가 또다른 프록시를 호출할 수 있는.. 뭐 그런거다.

 

@Slf4j
public class TimeDecorator implements Component{
    private Component component;


    public TimeDecorator(Component component) {
        this.component = component;
    }

    @Override
    public String operation() {
        log.info("TimeDecorator 실행");
        long startTime = System.currentTimeMillis();
        String result = component.operation();
        long endTime = System.currentTimeMillis();
        long resultTime = endTime - startTime;
        log.info("TimeDecorator 종료 resultTime={}ms", resultTime);
        return result;
    }
}

경과시간을 출력하는 데코레이터를 만들었다.

 

@Test
void decorator2(){
    Component realComponent = new RealComponent();
    Component messageDecorator = new MessageDecorator(realComponent);
    Component timeDecorator = new TimeDecorator(messageDecorator);
    DecoratorPatternClient client = new DecoratorPatternClient(timeDecorator);

    client.execute();
}

이렇게 데코레이터를 순서대로 겹겹이 넣어주면 된다.

 

아마 대부분 원본의 객체는 최하위에.

 

 

 

데코레이터 패턴은 이렇게 원본 컴포넌트와, 데코레이터(꾸며주는 컴포넌트) 이렇게 2종류가 존재.

 

 

참고로, 모양은 변형될 수 있으며,

의도와 목적이 맞다면 같은 디자인 패턴이라고 할 수 있다.