내가 공부한것을 올리며, 중요한 단원은 저 자신도 곱씹어 볼겸 상세히 기록하고 얕은부분들은 가겹게 포스팅 하겠습니다.
![[Spring] 데코레이터 패턴 [Spring] 데코레이터 패턴](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
1. 데코레이터 패턴 - 예제 코드1
간단하게 예제 코드를 만들어보자! 이전 Proxy 패턴과 거의 유사하다.
또한 코드가 매우 간단하여 설명은 생략한다.
![[Spring] 데코레이터 패턴 -
1. 데코레이터 패턴 - 예제 코드1
[Spring] 데코레이터 패턴 -
1. 데코레이터 패턴 - 예제 코드1](http://t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png)
▶ Component
public interface Component {
String operation();
}
▶ RealComponent
@Slf4j
public class RealComponent implements Component {
@Override
public String operation() {
log.info("RealComponent 실행");
return "data";
}
}
▶ DecoratorPatternClient
@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);
}
}
이를 실행하는 테스트 코드는 다음과 같다.
@Slf4j
public class DecoratorPatternTest {
@Test
public void no_decorator_test() {
RealComponent component = new RealComponent();
DecoratorPatternClient client = new DecoratorPatternClient(component);
client.execute();
}
}
실핼 결과는 다음과 같다.
![[Spring] 데코레이터 패턴 -
1. 데코레이터 패턴 - 예제 코드1
[Spring] 데코레이터 패턴 -
1. 데코레이터 패턴 - 예제 코드1](https://blog.kakaocdn.net/dn/q01iF/btrJlWggFqp/iJBHXkChpCKKEkSB6DBjKk/img.png)
2. 데코레이터 패턴 - 예제 코드2
앞서 프록시 패턴에서 캐시를 통한 접근 제어를 알아보았다.
이번에는 프록시를 활용해서 부가 기능을 추가해보자. 이렇게 프록시로 부가 기능을 추가하는 것을 데코레이터 패턴이라 한다.
![[Spring] 데코레이터 패턴 -
2. 데코레이터 패턴 - 예제 코드2
[Spring] 데코레이터 패턴 -
2. 데코레이터 패턴 - 예제 코드2](https://blog.kakaocdn.net/dn/zJKVr/btrJpOajFeh/RWb8RQI7FTe0lRCo4nO8E1/img.png)
우리의 기존 메시지를 꾸며주는 처리를 하는 MessageDecorator를 만들어보자!
@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 decoratedResult = "***" + result + "***";
log.info("MessageDecorator 꾸미기 적용 전={}, 적용 후={}", result, decoratedResult);
return decoratedResult;
}
}
Component 인터페이스를 구현한다. 따라서 사용하는 Client는 RealComponent인지? MessageDecorator인지? 구별하지 못한다.
또한 프록시가 호출해야 하는 대상을 component 에 저장한다.
operation() 을 호출하면 프록시와 연결된 대상을 호출( component.operation()) 하고, 그 응답 값에 *** 을 더해서 반환한다.
이를 테스트 코드를 통하여 확인해보자!
@Slf4j
public class DecoratorPatternTest {
@Test
void decorator1() {
Component realComponent = new RealComponent();
Component messageDecorator = new MessageDecorator(realComponent);
DecoratorPatternClient client = new DecoratorPatternClient(messageDecorator);
client.execute();
}
}
client -> messageDecorator -> realComponent 의 객체 의존 관계를 만들고, 실행한 결과는 다음과 같다.
![[Spring] 데코레이터 패턴 -
2. 데코레이터 패턴 - 예제 코드2
[Spring] 데코레이터 패턴 -
2. 데코레이터 패턴 - 예제 코드2](https://blog.kakaocdn.net/dn/brW7vt/btrJpe1qkNZ/dWykhme9DUq4mcvBpys2k1/img.png)
원래는 "data"라고만 출력되던 문자열이, "***data***"로 앞뒤에 별표가 추가되어 나온다.
3. 데코레이터 패턴 - 예제 코드3
이번에는 기존 데코레이터에 더해서 실행 시간을 측정하는 기능까지 추가해보자.
![[Spring] 데코레이터 패턴 -
3. 데코레이터 패턴 - 예제 코드3
[Spring] 데코레이터 패턴 -
3. 데코레이터 패턴 - 예제 코드3](https://blog.kakaocdn.net/dn/cDuHSy/btrJmwaOigX/bwjmK70sabfEOLGbeYIUCK/img.png)
실행 시간을 출력해주는 TimeDecorator를 만들어보자!
▶ TimeDecorator
@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={}", resultTime);
return result;
}
}
이를 사용하는 테스트 코드는 다음과 같다.
@Test
void decorator2() {
Component realComponent = new RealComponent();
Component messageDecorator = new MessageDecorator(realComponent);
TimeDecorator timeDecorator = new TimeDecorator(messageDecorator);
DecoratorPatternClient client = new DecoratorPatternClient(timeDecorator);
client.execute();
}
데코레이터를 연속하여 2개 사용하였다.
client -> timeDecorator -> messageDecorator -> realComponent 의 객체 의존관계를 설정하고 실행해보자!
출력 결과는 다음과 같다.
![[Spring] 데코레이터 패턴 -
3. 데코레이터 패턴 - 예제 코드3
[Spring] 데코레이터 패턴 -
3. 데코레이터 패턴 - 예제 코드3](https://blog.kakaocdn.net/dn/buTqwE/btrJlHcPuAo/5VYlfDN5UzjK21iKa8dXMk/img.png)
4. 프록시 패턴과 데코레이터 패턴 정리
우선 다음 그림을 살펴보자.
![[Spring] 데코레이터 패턴 -
4. 프록시 패턴과 데코레이터 패턴 정리
[Spring] 데코레이터 패턴 -
4. 프록시 패턴과 데코레이터 패턴 정리](https://blog.kakaocdn.net/dn/tX2bX/btrJo1Vqpo7/urByyBp1PZRvwLYyeCkLF0/img.png)
우리가 만든 Decorator들을 보면 코드에 중복된 부분이 있다.
꾸며주는 역할을 하는 Decorator 들은 스스로 존재할 수 없다. 항상 꾸며줄 대상이 있어야 한다.
따라서 Decorator는 내부에 호출 대상인 component 를 필수적으로 가지고 있어야 한다.
즉, component 를 필드로 가지고있고, 항상 호출해야 한다.
다음 코드 부분이 중복되는 것 이다.
public class xxxDecorator implements Component {
private Component component;
public MessageDecorator(Component component) {
this.component = component;
}
}
이런 중복을 제거하기 위해 component 를 속성으로 가지고 있는 Decorator 라는 추상 클래스를 만드는 방법도 고민할 수 있다.
이렇게 하면 추가로 클래스 다이어그램에서 어떤 것이 실제 컴포넌트 인지, 데코레이터인지 명확하게 구분할 수 있다.
여기까지 고민한 것이 바로 GOF에서 설명하는 데코레이터 패턴의 기본 예제이다.
더 자세한 데코레이터 패턴의 글은 다음 내가 정리해둔 글을 읽어보길 권장한다.
https://blogshine.tistory.com/7
[Design Patterns] Decorator Pattern : 데코레이터 패턴
Head First Design Patterns 책을 읽으며 정리한 내용 입니다. 문제가 될시 글을 내리도록 하겠습니다! Decorator Pattern 이란? Decorator Pattern - 객체에 추가적인 요건을 동적으로 첨가한다. 데코레이터는.....
blogshine.tistory.com
'BackEnd > Spring' 카테고리의 다른 글
[Spring] 동적 프록시 기술 - JDK, CGLIB (0) | 2022.08.13 |
---|---|
[Spring] 인터페이스, 구체 클래스 기반 프록시 (0) | 2022.08.10 |
[Spring] 프록시 패턴 (0) | 2022.08.10 |
[Spring] 프록시 패턴과 데코레이터 패턴 예제 (0) | 2022.08.09 |
[Spring] 템플릿 콜백 패턴 (0) | 2022.08.07 |
댓글