大家好✋,我是知识汲取者😄,今天给大家带来一篇有关装饰器模式的学习笔记。众所周知能够熟练使用设计模式是一个优秀程序猿的必备技能,当我们在项目中选择一个或多个合适的设计模式,不仅能大大提高项目的稳健性、可移植性、可维护性,同时还能让你的代码更加精炼,具备艺术美感。
俗话说”靠衣装,佛靠金装“,在代码的世界也是这样的,对象也需要通过穿“衣服”让对象变得更加“漂亮”,装饰器模式就是一个给对象穿“衣服”的角色,它可以通过给对象添加不同的“衣服”让对象的功能变得更加强大,以此完成更加复杂的功能。现在就让我们一起来学习这么一个有趣的模式吧😃
推荐阅读:
什么是装饰器模式?
装饰器模式(Decorator Pattern),也称包装器模式(Wrapper),是一种结构型模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构,具有很强的灵活性
装饰器模式的作用:动态1地给一个对象添加一些额外的职责
装饰器模式的优缺点
优点:
……
缺点:由于装饰器模式通过具体的装饰类增加对象的功能,这就会导致程序中增加许多功能类似的很小的类,进而增加系统的复杂度
……
装饰器模式的适用场景
……
生活中的应用:床衣服、戴首饰……凡是需要装饰的物品都是
Java中的应用:java.io包下的类就是使用装饰器模式实现的,我们可以对FileInputStream进行层层包装
装饰器模式的角色划分
PS:这些角色可以参考下面的案例进行理解
透明装饰器模式的特点是可以通过层层装饰,构件一个具有复杂功能的对象,但是客户端无法调用具体装饰器特有的功能
示例:
案例描述:手机分为简单手机、增强版手机、复杂版手机,简单手机在收到来电时只有一个响铃的功能,增强版手机收到来电相较简单手机会增加一个震动功能,复杂版手机相较于增强版手机收到来电时会增加一个闪光功能,现在使用装饰者模式来实现这三款手机

温馨提示:通过上面的类图可以发现测试类(这里模拟客户端)交互的类太多了,这是由于在Test中要创建大量的对象,其实这里也可以使用工厂模式进行优化,让测试类只与工厂类进行交互,从而进一步降低耦合度,但这里只是为了体验组合模式就不改造了,感兴趣的读者可以自行改造
Step1:创建抽象构件
package com.hhxy.phone;
/**
* @author ghp
* @date 2022/10/12
* @title
* @description
*/
public abstract class Phone {
/**
* 修饰方法
*/
public abstract void decorate();
}
Step2:创建具体构件
1)简单手机:
package com.hhxy.phone.ext;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/10/12
* @title 简单手机
* @description 只有响铃功能
*/
public class SimplePhone extends Phone {
/**
* 修饰方法
*/
@Override
public void decorate() {
System.out.println("的简单手机");
}
}
2)增强版手机
和简单手机的代码是类似的,详细代码请参考Github或Gitee仓库,略……
3)复杂版手机
和简单手机的代码是类似的,详细代码请参考Github或Gitee仓库,略……
Step3:创建抽象装饰者
package com.hhxy.decorator.transparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/10/12
* @title
* @description
*/
public class Decorator extends Phone{
protected Phone phone;
public Decorator(Phone phone){
this.phone = phone;
}
/**
* 修饰方法
*/
@Override
public void decorate() {
phone.decorate();
}
}
Step4:创建具体装饰者
1)添加响铃功能的装饰器
package com.hhxy.decorator.transparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/10/12
* @title 响铃装饰者
* @description 用于给手机添加响铃功能
*/
public class BellDecorator extends Decorator {
public BellDecorator(Phone phone) {
super(phone);
}
/**
* 修饰方法
*/
@Override
public void decorate() {
this.addBell();
super.decorate();
}
/**
* 添加响铃功能的方法
*/
private void addBell(){
System.out.print("响铃");
}
}
2)添加震动功能的装饰器
package com.hhxy.decorator.transparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/10/12
* @title 震动修饰者
* @description 用于给手机添加震动功能
*/
public class ShockDecorator extends Decorator {
public ShockDecorator(Phone phone) {
super(phone);
}
/**
* 修饰方法
*/
@Override
public void decorate() {
this.addShock();
super.decorate();
}
/**
* 添加震动的方法
*/
private void addShock(){
System.out.print("震动");
}
}
3)添加闪光功能的装饰器
package com.hhxy.decorator.transparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/10/12
* @title 闪光修饰类
* @description 用于给手机添加闪光功能
*/
public class FlashDecorator extends Decorator {
public FlashDecorator(Phone phone) {
super(phone);
}
/**
* 修饰方法
*/
@Override
public void decorate() {
this.addFlash();
super.decorate();
}
/**
* 添加闪光的方法
*/
private void addFlash(){
System.out.print("闪光");
}
}
Step5:编写测试类
package com.hhxy.test;
import com.hhxy.decorator.transparent.BellDecorator;
import com.hhxy.decorator.transparent.FlashDecorator;
import com.hhxy.decorator.transparent.ShockDecorator;
import com.hhxy.phone.Phone;
import com.hhxy.phone.ext.ComplexPhone;
/**
* @author ghp
* @date 2022/10/12
* @title 测试类1
* @description 用于测试透明装饰模式
*/
public class Test1 {
public static void main(String[] args) {
//三款不同类型的手机
Phone phone1,phone2,phone3;
//
Phone decorator1,decorator2,decorator3;
//简单手机
/*phone1 = new SimplePhone();
decorator1 = new BellDecorator(phone1);
decorator1.decorate();*/
//增强手机
/*phone2 = new EnhancePhone();
decorator1 = new BellDecorator(phone2);
decorator2 = new ShockDecorator(decorator1);
decorator2.decorate();*/
//复杂手机
phone3 = new ComplexPhone();
decorator1 = new BellDecorator(phone3);
decorator2 = new ShockDecorator(decorator1);
decorator3 = new FlashDecorator(decorator2);
decorator3.decorate();
}
}
测试结果:

半透明装饰器模式是最常见的装饰器模式,它和对象适配器模式的是十分相似的,不同之处在于适配器模式是兼容接口,让一个都对象能调用另一个对象的方法,而对象适配器是为了让一个对象增加一个新的功能。所以也可以称半透明装饰器模式为版适配器半装饰器模式。
关于对象适配器模式可以参考这篇文章: 每日一个设计模式之【适配器模式】
示例:
我们依然以上面一个示例为基准,使用半透明装饰器模式来实现

Step1:创建抽象构件
和透明装饰器模式的代码一致,略……
Step2:创建具体构件
和透明装饰器模式的代码一致,略……
Step3:创建抽象装饰者
package com.hhxy.decorator.untransparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/10/12
* @title
* @description
*/
public class Decorator extends Phone{
protected Phone phone;
public Decorator(Phone phone){
this.phone = phone;
}
/**
* 修饰方法
*/
@Override
public void decorate() {
phone.decorate();
}
}
Step4:创建具体装饰者
1)简单手机装饰者
package com.hhxy.decorator.untransparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/11/14
* @title
* @description
*/
public class SimpleDecorator extends Decorator{
public SimpleDecorator(Phone phone) {
super(phone);
}
/**
* 修饰方法
*/
@Override
public void decorate() {
this.addBell();
super.decorate();
}
/**
* 添加响铃功能
*/
public void addBell(){
System.out.print("响铃");
}
}
2)增强版手机装饰者
package com.hhxy.decorator.untransparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/11/14
* @title
* @description
*/
public class EnhanceDecorator extends Decorator{
public EnhanceDecorator(Phone phone) {
super(phone);
}
/**
* 修饰方法
*/
@Override
public void decorate() {
this.addBell();
this.addShock();
super.decorate();
}
/**
* 添加响铃功能
*/
public void addBell(){
System.out.print("响铃");
}
/**
* 添加震动功能
*/
public void addShock(){
System.out.print("震动");
}
}
3)复杂版手机装饰者
package com.hhxy.decorator.untransparent;
import com.hhxy.phone.Phone;
/**
* @author ghp
* @date 2022/11/14
* @title
* @description
*/
public class ComplexDecorator extends Decorator{
public ComplexDecorator(Phone phone) {
super(phone);
}
/**
* 修饰方法
*/
@Override
public void decorate() {
this.addBell();
this.addShock();
this.addFlash();
super.decorate();
}
/**
* 添加响铃功能
*/
public void addBell(){
System.out.print("响铃");
}
/**
* 添加震动功能
*/
public void addShock(){
System.out.print("震动");
}
/**
* 添加闪光功能
*/
public void addFlash(){
System.out.print("闪光");
}
/**
* 该装饰者类中特有的功能
*/
public void special(){
System.out.println("这是ComplexDecorator特有的功能");
}
}
Step5:编写测试类
package com.hhxy.test;
import com.hhxy.decorator.untransparent.ComplexDecorator;
import com.hhxy.phone.Phone;
import com.hhxy.phone.ext.ComplexPhone;
/**
* @author ghp
* @date 2022/11/14
* @title 测试类2
* @description 用于测试半透明装饰器模式
*/
public class Test2 {
public static void main(String[] args) {
Phone phone = new ComplexPhone();
ComplexDecorator complexDecorator = new ComplexDecorator(phone);
complexDecorator.decorate();
complexDecorator.special();
}
}
测试结果:

透明装饰器模式和半透明装饰器模式的比较:
总的而言,装饰器模式核心实现是利用委托机制,相较于传统的继承机制,能够更加灵活地去扩展功能。其中半透明装饰器模式是最常见的装饰器模式,它是介于适配器模式和装饰器模式之间的,而透明装饰器模式是一种理想的装饰器模式,它的设计难度更大。
自此,文章就结束了,如果觉得本文对你有一丢丢帮助的话😄,欢迎点赞👍+评论✍,您的支持将是我写出更加优秀文章的动力O(∩_∩)O

上一篇:每日一个设计模式之【组合模式】
下一篇:每日一个设计模式之【外观模式】
参考文章:
- 装饰器模式 | 菜鸟教程 (runoob.com)
- 装饰器模式的使用总结
- 廖雪峰的个人博客-装饰器模式
- 装饰者模式(Decorator Pattern) - 知乎 (zhihu.com)
- 设计模式详解——装饰者模式
在次致谢
动态:这里的动态是指在代码运行时,对象就多了一个新功能,而在编译阶段对象是不具有该功能,可以类比动态语言的定义 ↩︎