데코레이터 패턴
데코레이터 패턴은 타깃에 부가적인 기능을 런타임 시 다이내믹하게 부여해주기 위해 프록시를 사용하는 패턴을 말한다.
다이내믹하게 기능을 부가한다는 의미는 컴파일 시점,
즉 코드상에서 어떤 방법과 순서로 프록시와 타깃이 연결되어 사용되는지 정해져 있지 않다는 것이다.
데코레이터라고 불리는 이유
- 마치 제품이나 케익 등의 여러 겹으로 포장하고 그 위에 장식을 붙이는 것처럼 실제 내용물은 동일하지만 부가적인 효과를 부여해 줄수 있기 때문이다.
따라서 테코레이터 패턴에서는 프록시가 꼭 한 개로 제한되지 않는다.
또한 프록시가 직접 타깃을 사용하도록 고정시킬 필요도 없다.
예제
A라는 인터페이스가 있고 B,C라는 구현제가 있다.
B가 핵심 기능을 담당하고 C가 부가 기능을 담당한다.
C는 B를 주입받아 B에게 핵심 기능을 위임하고 자신은 부가 기능에 대해 처리한다.
A(UserService) 라는 인터페이스가 있고 B(UserServiceImple) ,C(UserServiceTx) 라는 구현제가 있다.
B(UserServiceImple)가 핵심 기능(User 관리 로직) 을 담당하고 C(UserServiceTx)가 부가 기능(트랜잭션 관리)를 담당한다.
C(UserServiceTx)는 B(UserServiceImple)를 주입받아 B(UserServiceImple)에게 핵심 기능을 위임하고
자신은 부가 기능에 대해 처리한다.
public interface UserService {
void add(User user);
void upgradeLevels();
}
public class UserServiceTx implements UserService{
PlatformTransactionManager transactionManager;
UserService userService;
public void setUserService(UserService userService){
this.userService = userService;
}
public void setTransactionManager(PlatformTransactionManager transactionManager){
this.transactionManager = transactionManager;
}
@Override
public void add(User user) {
this.userService.add(user);
}
@Override
public void upgradeLevels() {
TransactionStatus status = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
try{
this.userService.upgradeLevels();
this.transactionManager.commit(status);
}catch(RuntimeException e){
this.transactionManager.rollback(status);
throw e;
}
}
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void upgradeLevels() {
List<User> users = userDao.getAll();
for (User user : users) {
if (canUpgradeLevel(user)) {
upgradeLevel(user);
}
}
}
protected void upgradeLevel(User user) {
user.upgradeLevel();
userDao.update(user);
}
public void add(User user) {
if (user.getLevel() == null) user.setLevel(Level.BASIC);
userDao.add(user);
}
}
@Autowired UserService userService;
@Test
public void DecoratorTest(){
userService.upgradeLevels();
}
// 데코레이터 패턴을 위한 DI 설정
<bean id="userService" class="user.service.UserServiceTx">
<property name="transactionManager" ref="transactionManager" />
<property name="userService" ref="userServiceImpl" />
</bean>
<bean id="userServiceImpl" class="user.service.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
데코레이터 패턴은 인터페이스를 통해 위임하는 방식이기 때문에
코드 레벨에서는 어느 타깃(데코레이터)로 연결될지 모른다.
구성하기에 따라 여러 개의 데코레이터를 적용 될 수가 있다.
구조적으로 보자면 프록시와 데코레이터는 유사하지만
프록시는 코드에서 자신이 만들거나 접근할 타킷 클래스 정보를 알고 있는 경우가 많다.
'Dev > etc' 카테고리의 다른 글
메타프로그래밍 (0) | 2023.02.19 |
---|---|
데이터 중심 아키텍처(DB/SQL 중심) (0) | 2023.02.08 |
전략패턴 (0) | 2022.12.02 |
TDD에서 테스트 문서 대체 가능이란? (0) | 2022.10.30 |
Semantic Versioning (0) | 2022.10.01 |