1. 理论
装饰器(Decorator)模式:允许向一个现有的对象添加新的功能,同时又不改变器其结构。
这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供额外的功能。
意图:Decorator模式采用对象组合而非继承的方式,实现了动态的扩展对象功能的能力。而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“大量子类”的问题。
使用场景:在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。处理那些可以撤销的职责。
- 当不能采用生成子类的方式进行扩展时。一种情况是:可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
- (重写源码)因为类定义被隐藏,或类定义不能用于生成子类。
代理模式和装饰器模式的区别
在装饰器模式中,必须有被装饰的类和装饰的类。代理模式一定是自身持有这个对象,不需要从外部传入。而装饰模式一定是从外部传入(即代理模式的目标对象不对外,代理对象全权处理;装饰器模式是辅助,目标仍然可以对外提供服务,装饰器模式只是增强作用),并且可以没有顺序,按照代码的试卷需要随意挑换顺序。
从使用上,代理模式注重隔离限制,让外部不能方法实际调用对象,比如权限控制,装饰模式注重的是功能的扩展,在一个方法下实现更多的功能。
2. 项目实际用法
接口类型(Component):给出一个抽象类接口,以规范准备接收附加责任的对象
/**
* 具体的业务接口
*/
public interface MappingBusinessService {
/**
* 接口的方法
*/
ItemAnswerResp assembleItemAndAnswer(OriResult oriResult, PlanInfoDto planInfoDto);
}
具体子类(ConcreteCompoent):定义一个业务接口的具体实现:
而实际业务中,可以多种设计模式组合使用,此处使用“模板方法模式”来实现。
/**
* 模板方式——将大逻辑拆分为小逻辑。
*/
@Slf4j
public abstract class AbstractMappingBusinessService implements MappingBusinessService {
@Override
public ItemAnswerResp assembleItemAndAnswer(OriResult oriResult, PlanInfoDto planInfoDto) {
//数据校验
validateHandler(planInfoDto);
//数据准备
prepareHandler(planInfoDto);
//获取做的记录
List<ItemAnswerDto> itemAnswerInfo = getItemAnswerInfo(planInfoDto);
log.info(JSON.toJSONString(itemAnswerInfo));
return null;
}
/**
* 子类必须实现的抽象方法
*/
public abstract List<ItemAnswerDto> getItemAnswerInfo(PlanInfoDto planInfoDto);
/**
* 校验器
*/
protected void validateHandler(PlanInfoDto planInfoDto){
}
/**
* 数据准备器
*/
protected void prepareHandler(PlanInfoDto planInfoDto){
log.info("AbstractMappingBusinessService的数据准备");
}
}
/**
* 二级父类
*/
@Slf4j
public abstract class AbstractSimpleMappingBusinessService extends AbstractMappingBusinessService {
/**
* 某些业务场景下,可能存在多级父类情况
*/
protected void prepareHandler(PlanInfoDto planInfoDto) {
super.prepareHandler(planInfoDto);
log.info("AbstractSimpleMappingBusinessService的数据准备");
}
}
具体的子类,子类已经在Spring容器中。
/**
* 具体子类
*/
@Service
@Slf4j
public class MappingBusinessServiceImpl3 extends AbstractSimpleMappingBusinessService {
@Override
public List<ItemAnswerDto> getItemAnswerInfo(PlanInfoDto planInfoDto) {
ItemAnswerDto itemAnswerDto = new ItemAnswerDto();
itemAnswerDto.setName("亚瑟");
ItemAnswerDto itemAnswerDto2 = new ItemAnswerDto();
itemAnswerDto2.setName("韩信");
return Arrays.asList(itemAnswerDto, itemAnswerDto2);
}
}
装饰器类
装饰器类和具体实现继承的是同一接口。
/**
* 装饰器
*/
@Slf4j
public class LogMappingBusinessDecorator implements MappingBusinessService {
private MappingBusinessService mappingBusinessService;
public LogMappingBusinessDecorator(MappingBusinessService mappingBusinessService) {
this.mappingBusinessService = mappingBusinessService;
}
@Override
public ItemAnswerResp assembleItemAndAnswer(OriResult oriResult, PlanInfoDto planInfoDto) {
log.info("日志装饰器增加可以被撤销的职责");
return mappingBusinessService.assembleItemAndAnswer(oriResult, planInfoDto);
}
}
疑问?装饰器类能实现抽象类接口吗?
是可以的。装饰器类可以实现抽象类。来动态的扩展抽象类。
但是实现的抽象父类必须重写所有的非private
方法。
/**
* 实现抽象类接口的装饰器对象
*/
@Slf4j
public class MappingValidateDecorator extends AbstractMappingBusinessService{
private AbstractMappingBusinessService abstractMappingBusinessService;
public MappingValidateDecorator(AbstractMappingBusinessService abstractMappingBusinessService) {
this.abstractMappingBusinessService = abstractMappingBusinessService;
}
@Override
public List<ItemAnswerDto> getItemAnswerInfo(PlanInfoDto planInfoDto) {
return abstractMappingBusinessService.getItemAnswerInfo(planInfoDto);
}
/**
* 虽然该装饰器不是处理"数据准备处理器",但是必须原样返回子类的配置(除private方法)。
* 否则子类将继承抽象类的配置。这可能会导致问题。
*
*/
@Override
protected void prepareHandler(PlanInfoDto planInfoDto) {
abstractMappingBusinessService.prepareHandler(planInfoDto);
}
@Override
protected void validateHandler(PlanInfoDto planInfoDto) {
abstractMappingBusinessService.validateHandler(planInfoDto);
log.info("---->校验处理器:MappingValidateDecorator");
}
}
(核心)装饰后放入到Spring容器中
可以灵活的被多个装饰器装饰,动态的扩展功能。
/**
* 放入到Spring容器中
*/
@Configuration
public class MappingConfig {
@Bean("mappingDecorator1")
public MappingBusinessService getV1(MappingBusinessServiceImpl1 mappingBusinessServiceImpl1){
return new MappingDecorator(mappingBusinessServiceImpl1);
}
@Bean("mappingValidateDecorator2")
public MappingBusinessService getV2(MappingBusinessServiceImpl2 mappingBusinessServiceImpl2){
return new MappingValidateDecorator(mappingBusinessServiceImpl2);
}
@Bean("mappingValidateDecorator3")
public MappingBusinessService getV3(MappingBusinessServiceImpl3 mappingBusinessServiceImpl3){
return new LogMappingBusinessDecorator(new MappingValidateDecorator(mappingBusinessServiceImpl3));
}
}
(核心)路由枚举
动态的获取Spring对象。
注:创建的是装饰器对象。
@Getter
public enum MappingEnum {
V1(1, "mappingDecorator1"),
V2(2, "mappingValidateDecorator2"),
V3(3, "mappingValidateDecorator3");
private Integer type;
private String clazz;
MappingEnum(Integer type, String clazz) {
this.type = type;
this.clazz = clazz;
}
public static MappingEnum resolve(Integer type) {
for (MappingEnum mappingEnum : values()) {
if (mappingEnum.type.equals(type)) {
return mappingEnum;
}
}
throw new RuntimeException("类型不存在");
}
public static MappingBusinessService getBean(Integer type) {
return SpringUtils.getBean(resolve(type).clazz, MappingBusinessService.class);
}
}
借助的工具类。
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
public static <T> T getBean(Class<T> c) {
return getApplicationContext().getBean(c);
}
public static <T> T getBean(String name, Class<T> c) {
return getApplicationContext().getBean(name, c);
}
}
测试
@RestController
public class TestMappingController {
@PostMapping("test1")
public void test(@RequestParam("type") Integer type){
MappingBusinessService bean = MappingEnum.getBean(type);
ItemAnswerResp itemAnswerResp = bean.assembleItemAndAnswer(null, null);
}
}
效果:
(LogMappingBusinessDecorator.java:25): 日志装饰器增加可以被撤销的职责
(MappingValidateDecorator.java:41): ---->校验处理器:MappingValidateDecorator
(AbstractMappingBusinessService.java:44): AbstractMappingBusinessService的数据准备
(AbstractSimpleMappingBusinessService.java:20): AbstractSimpleMappingBusinessService的数据准备
(AbstractMappingBusinessService.java:25): [{"name":"亚瑟"},{"name":"韩信"}]
网友评论