Decorator Pattern

종원유·2022년 3월 13일
0

Java

목록 보기
10/11

데코레이터 패턴

프록시 패턴과 데코레이터 패턴

프록시 패턴 : https://velog.io/@yjw8459/Proxy-Pattern

구분

기존에 있는 것을 꾸미다, 추가한다는 의미의 데코레이터 패턴은 프록시 패턴과 굉장히 유사하고, 상황에 따라서는 같은 경우도 있다.
디자인 패턴에서 중요한 것은 해당 패턴의 겉모양이 아니라 그 패턴을 만든 의도가 더 중요한데, 프록시 패턴과 데코레이터 패턴의도로 구분한다.

  • 프록시 패턴의 의도 : 다른 개체에 대한 접근을 제어하기 위해 대리자를 제공
  • 데코레이터 패턴의 의도 : 객체에 추가 책임(기능)을 동적으로 추가하고, 확장을 위한 유연한 대안 제공

데코레이터 패턴과 프록시 패턴의 구분 정리
프록시를 사용하고 해당 프록시가 접근 제어가 목적이라면 프록시 패턴이고, 새로운 기능을 추가하는 것이 목적이라면 데코레이터 패턴이 된다.

부가 기능 추가

  • 프록시로 할 수 있는 기능은 크게 접근 제어와 부가 기능 추가라는 2가지로 구분한다.
    • 접근 제어
    • 부가 기능 추가
  • 데코레이터 패턴은 프록시를 활용하여 부가 기능을 추가한다.
    • 요청 값이나, 응답 값을 중간에 변형
    • 실행 시간을 측정해서 추가 로그를 남긴다.

데코레이터 패턴 적용 전


런타임 객체 의존 관계

//Server Interface
public interface Component {
    String operation();
}

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

//Client
@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);

    }
}

  • 테스트 코드
    /**
     * Client -> RealComponent 의존관계 설정
     */
    @Test
    void noDecorator(){
        Component realComponent = new RealComponent();
        DecoratorPatternClient client = new DecoratorPatternClient(realComponent);
        client.execute();
    }
  • 출력 결과

데코레이터 패턴 적용 전 Client -> RealComponent 의존 관계이다.

데코레이터 패턴 적용 후

  • 런타임 객체 의존 관계

  • MessageDecorator

//Decorator
@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();
        //result -> *****data*****
        String decoResult = "*****" + result + "*****";
        log.info("MessageDecorator 꾸미기 적용 전 = {}, 적용 후={}", result, decoResult);
        return decoResult;
    }
}
  • 테스트 코드
    /**
     * Client -> MessageDecorator -> RealComponent
     */
    @Test
    void decorator1(){
        Component realComponent = new RealComponent();
        Component messageDecorator = new MessageDecorator(realComponent);
        DecoratorPatternClient client = new DecoratorPatternClient(messageDecorator);
        client.execute();
    }
  • 출력결과

Client에 messageDecorator를 주입하면서
Client -> MessageDecorator -> RealComponent의존 관계로 설정한다.

여러 데코레이터 패턴 적용

데코레이터 패턴은 클라이언트와 서버를 변경하지 않고, 여러 부가 기능으로 꾸미는 것이 특징이다.

  • 런타임 객체 의존 관계

  • TimeDecorator

@Slf4j
public class TimeDecorator implements Component{

    private Component component;

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


    /**
     * 실행시간 측정 부가 기능
     * @return
     */
    @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 종료 resultTome={}ms", resultTime);
        return result;
    }
}
  • 테스트 코드
    /**
     * Client -> TimeDecorator -> MessageDecorator -> RealComponent
     */
    @Test
    void decorator2(){
        Component realComponent = new RealComponent();
        Component messageDecorator = new MessageDecorator(realComponent);
        Component timeDecorator = new TimeDecorator(messageDecorator);
        DecoratorPatternClient client = new DecoratorPatternClient(timeDecorator);
        client.execute();
    }
  • 출력결과

Client에 TimeDecorator를 주입하고, TimeDecorator는 MessageDecorator를 의존하면서
Client -> TimeDecorator -> MessageDecorator -> RealComponent의존 관계로 설정한다.

정리

데코레이터 패턴을 이용하면 기존 코드를 수정하지 않고 여러 추가 책임(기능)을 추가하여 확장을 위한 유연한 대안을 제공할 수 있다.

profile
개발자 호소인

0개의 댓글