装饰模式
定义:
装饰模式是一种结构型设计模式, 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。
现实举例:
拿穿衣服举例子,比如你现在穿着一件上衣,但是天气冷了,你给自己套个“毛衣”,但是感觉脖子冷,再给自己套个“围巾”,觉得还是不够保暖,再给自己套个“羽绒服”,这些衣物都 “扩展” 了你的基本行为, 但它们并不是你的一部分, 如果你不再需要某件衣物, 可以方便地随时脱掉。
适用场景
- 如果你希望在无需修改原有代码的情况下即可使用对象, 且希望在运行时为对象新增额外的行为, 可以使用装饰模式。
- 如果用继承来扩展对象行为的方案难以实现或者根本不可行, 你可以使用该模式。
与其他设计模式的关系
- 适配器能为被封装对象提供不同的接口, 代理模式能为对象提供相同的接口, 装饰模式则能为对象提供加强的接口。
- 装饰和代理有着相似的结构, 但是其意图却非常不同。 这两个模式的构建都基于组合原则, 也就是说一个对象应该将部分工作委派给另一个对象。 两者之间的不同之处在于代理模式通常自行管理其服务对象的生命周期, 而装饰的生成则总是由客户端进行控制。
在SpringBoot的使用
举例:比如有个简单的视频播放功能,希望在简单的视频播放功能基础上,加上美颜、贴图等增强功能
1. 新增测试基础服务
(1)新增接口,提供播放服务
public interface VideoService {
void play();//播放视频
}
(2)新增VideoServiceImpl实现上面接口
@Service
public class VideoServiceImpl implements VideoService {
@Override
public void play() {
System.out.println("播放视频");
}
}
(3)新增测试Controller,调用该接口
@RestController
public class VideoController {
@Resource(name = "videoService")
VideoService videoService;
@GetMapping("/default_video")
public String defaultVideo(String decorate){
videoService.play();
return "原有的播放逻辑";
}
}
2. 扩充服务
需求:现在需要在播放视频的基础上,加上特效如美颜、贴图,但是不要影响到原本的功能使用,可选择的给视频加上美颜、贴图两个功能
(1)新增视频装饰器抽象基类,实现了VideoService
/**
* @author 勤任风
* @date 2021-04-11 14:26
*/
public abstract class VideoDecorator implements VideoService {
private VideoService videoService;
public VideoDecorator(VideoService videoService) {
this.videoService = videoService;
}
@Override
public void play() {
this.videoService.play(); //播放视频
}
}
(2)给这个装饰器基类加上扩展功能,新增两个装饰器:美颜装饰、贴图装饰
/**
* 视频美颜装饰器
* @author 勤任风
* @date 2021-04-11 14:22
*/
@Service
public class VideoDecoratorA extends VideoDecorator {
public VideoDecoratorA(VideoService videoService) {
super(videoService);
}
/**
* 加强的逻辑:加上美颜
*/
public void decorate(){
System.out.println("装饰:加上美颜");
}
@Override
public void play(){
this.decorate();
super.play();
}
}
/**
* 视频贴图装饰器
* @author 勤任风
* @date 2021-04-11 14:22
*/
@Service
public class VideoDecoratorB extends VideoDecorator {
public VideoDecoratorB(VideoService videoService) {
super(videoService);
}
/**
* 加强的逻辑:加上贴图
*/
public void decorate(){
System.out.println("装饰:加上卡通贴图");
}
@Override
public void play(){
this.decorate();
super.play(); //原有的视频播放逻辑
}
}
(3)创建Bean
/**
* @author 勤任风
* @date 2021-04-11 14:54
*/
@Configuration
public class decorateConfig {
@Bean("videoService")
VideoService videoService(){
return new VideoServiceImpl();
}
@Bean("decoratorA")
VideoDecoratorA videoDecoratorA(@Qualifier("videoService") VideoService videoService){
return new VideoDecoratorA(videoService);
}
@Bean("decoratorB")
VideoDecoratorB videoDecoratorB(@Qualifier("videoService") VideoService videoService){
return new VideoDecoratorB(videoService);
}
}
(4)再改下Controller,测试功能
/**
* @author 勤任风
* @date 2021-04-11 14:21
*/
@RestController
public class VideoController {
@Resource(name = "videoService")
VideoService videoService;
@Resource(name = "decoratorA")
VideoService videoDecoratorA; //加上了滤镜的装饰类
@Resource(name = "decoratorB")
VideoService videoDecoratorB; //加上了贴图的装饰类
@GetMapping("/video")
public String video(String decorate){
if("1".equals(decorate)){
videoDecoratorA.play();
return "装饰者模式:播放视频-加上美颜滤镜";
}else{
videoDecoratorB.play();
return "装饰者模式:播放视频-加上卡通贴图";
}
}
@GetMapping("/default_video")
public String defaultVideo(String decorate){
videoService.play();
return "原有的播放逻辑";
}
}
(5)调用接口测试
- 给视频加上美颜
- 给视频加上贴图