전 글에도 언급했다시피 프록시를 사용하는 두가지 GOF 디자인 패턴에는
프록시 패턴과 데코레이터 패턴이 있다.
그 중 데코레이터 패턴은 새로운 기능 추가가 목적인 디자인 패턴이다.
예시 코드에서는 operation이라는 명칭의 메소드로 기능 추가 구현을 했다.
데코레이터 패턴 (기능 추가) 를 적용하기 전에 간결한 예시 코드를 먼저 보자.
public interface Component {
String operation();
}
Component라는 인터페이스를 RealComponent라는 구현체로 구현한다.
그러기 위해서는 RealComponent에서 operation이라는 메소드 내부에 코드를 구현해야한다.
코드로 표현하면 다음과 같다.
public class RealComponent implements Component {
@Override
public String operation() {
log.info("RealComponent 실행");
return "data";
}
}
public class DecoratorPatternClient {
private Component component;
public DecoratorPatternClient(Component component) {
this.component = component;
}
public void execute() {
String result = component.operation();
log.info("result={}", result);
}
}
기존 템플릿메서드 패턴의 특징인 익명클래스 대신 전체적으로 인터페이스를 활용하는 형태의 코드이다.
인터페이스를 활용하면 상속의 단점을 벗어날 수 있다.
해당 코드의 최종 실행은 다음과 같이 한다.
public class DecoratorPatternTest {
@Test
void noDecorator() {
// Component 구현체로 RealComponent 지정
Component realComponent = new RealComponent();
// 실제 operation할 구현체로 RealComponent로 생성자 전달
DecoratorPatternClient client = new DecoratorPatternClient(realComponent);
client.execute();
}
}
위와 같은 프로세스의 로직에 다른 로그를 찍는 기능을 추가할 것이다.
앞서 말했다시피 데코레이터 패턴은 기능을 추가하는 디자인 패턴이다.
이후 코드에서 기능을 하나씩 추가해보겠다.
그림에서와 같이 필터처럼 중간에 기능을 하나 추가하는 형태이다.
추가할 기능도 결국 Component라는 인터페이스의 구현체로 만들 것이기 때문에 실행만 연속적으로 잘해준다면 도미노와 같이 추가 실행이 가능하다.
이에 대한 코드는 다음과 같다.
Component 인터페이스의 구현체로 MessageDecorator를 새로 만들고,
MessageDecorator 안에서 다음 실행될 RealComponent를 실행해 연속으로 실행될 수 있도록 한다.
public class MessageDecorator implements component {
private Component component;
public MessageDecorator(Component component) {
this.component = component;
}
@Override
public String operation() {
// MessageDecorator 만의 기능 추가
log.info("MessageDecorator 실행");
// 다음 단계 operation 실행을 통해 도미노 연쇄 작용
String result = component.operation();
String decoResult = "@@@" + result + "@@@";
log.info("MessageDecorator 적용 전={}, 적용 후={}", result, decoResult);
// 기능을 추가한 결과를 반환
return decoResult;
}
}
void decorator1() {
Component realComponent = new RealComponent();
// MessageDecorator의 생성자 파라미터로 다음 실행될(기존 구성) realComponent를 전달
Component messageDecorator = new MessageDecorator(realComponent);
DecoratorPatternClient client = new DecoratorPatternClient(messageDecorator);
// 도미노 스타트
client.execute();
}
여기서 한단계 더 나아가 다른 기능을 하나 더 추가해보자.
도미노 하나 더 뒤에 쌓는다고 생각하면 된다.
public class TimeDecorator implements Component {
private Component component;
public TimeDecorator(Component component) {
this.component = component;
}
@Override
public String operation() {
// TimeDecorator만의 로직 실행
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;
}
}
실행 코드도 도미노 하나만 더 세워주는 형태이다.
다음과 같다.
void decorator2() {
Component realComponent = new RealComponent();
// 바톤 터치
Component messageDecorator = new MessageDecorator(realComponent);
Component timeDecorator = new TimeDecorator(messageDecorator);
DecoratorPatternClient client = new DecoratorPatternClient(timeDecorator);
client.execute();
}
도미노도 같은 모양에 올바른 위치에 세워주면 연쇄적으로 동일한 작동을 한다.
데코레이터 패턴도 동일하게 작동한다.
같은 틀(인터페이스)로 찍어낸 도미노들(구현체)을 생성자를 통해 연쇄적으로 배치시켜주면 계속 기능 추가를 할 수 있다.
'Computer Science > Design Pattern' 카테고리의 다른 글
[디자인 패턴] 프록시 패턴 (feat. Spring) (0) | 2023.12.28 |
---|---|
[디자인 패턴] 전략 패턴 (feat. Spring) (0) | 2023.12.22 |
[디자인 패턴] 템플릿 메서드 패턴 (feat. Spring) (0) | 2023.12.14 |
이터레이터 패턴(Iterator Pattern) (0) | 2022.07.05 |
팩토리 패턴 (0) | 2022.07.05 |