引言

装饰者模式,又叫装饰器模式。它可以动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更灵活,同时装饰者模式也体现了OCP原则

在客户端调用使用了装饰者模式的对象时,就好像在使用构造器层层包裹核心对象,层层装饰核心对象,因此叫做装饰者模式。

一、装饰者模式类图

装饰者模式属于结构型设计模式。在JDK的IO流API中,就利用了装饰者模式:

以简单的形状和颜色为例。如何为不同的形状装饰新的颜色呢?

上图中,Shape和ShapeDecorator都是抽象类,一般情况下,装饰者模式中的顶层装饰器类(ShapeDecorator)一定要是抽象类,因为它需要维护被装饰者,并重写特定行为。客户端在调用的时候,并不会直接使用它,而是会使用具体的装饰器类(Red、White)。

Shape类在本例中是一个抽象类,实际上也可以是一个接口,主要看有没有需要维护的属性。接口中是不允许有属性的,所以如果需要维护一些公共属性,那么可以采用抽象类,而如果只是封装了行为,那么建议采用接口。

装饰者模式的精髓在于,装饰者模式将继承和组合两种技巧相结合。

继承的目的是为了可以在原来的位置上取代被装饰对象(前提是调用方使用的是父类引用)。

组合(采用构造器传入一个被装饰对象,并在内部维护这个对象属性)的目的是可以在核心对象的基础之上加以装饰,即保留原来的核心对象的特征和行为,只做扩展,不做修改(OCP原则)。

装饰器子类在重写被装饰者的特定行为时,一定要注意,根据业务是否需要严格遵守对原来对象行为的扩展,而不是修改。如果是只扩展不修改,那么一定要在抽象装饰器类中调用被装饰对象的方法,并在装饰器子类的方法中使用“super.”的形式间接调用被装饰者的方法,然后根据装饰需要,在调用的前后执行装饰逻辑。如果业务设计上允许对原有行为作出一些修改,那么其实并没有严格遵守OCP原则,这种情况下,抽象装饰器类的对原对象方法的调用可以视情况而定修改甚至忽略。后者违背OCP原则的方式不建议使用装饰者模式来完成。

二、装饰者模式代码实现

/*** 图形接口*/
public abstract class Shape {protected String name;public abstract void draw();public String getName() {return name;}
}
public class Circle extends Shape {public Circle() {name = "圆形";}@Overridepublic void draw() {System.out.println(name);}
}
public class Square extends Shape {public Square() {name = "正方形";}@Overridepublic void draw() {System.out.println(name);}
}
/*** 装饰器抽象类*/
public abstract class ShapeDecorator extends Shape {protected Shape decoratedShape;public ShapeDecorator(Shape shape) {this.decoratedShape = shape;}@Overridepublic void draw() {decoratedShape.draw();}
}
public class Red extends ShapeDecorator {public Red(Shape shape) {super(shape);}@Overridepublic void draw() {paint();}// 随意增加想要装饰在核心对象上的功能private void paint() {System.out.println("红色的" + decoratedShape.getName());}
}
public class White extends ShapeDecorator {public White(Shape shape) {super(shape);}@Overridepublic void draw() {paint();}private void paint() {System.out.println("白色的" + decoratedShape.getName());}
}

测试代码:

public class Client {public static void main(String[] args) {Shape redCircle = new Red(new Circle());redCircle.draw();Shape whiteCircle = new White(new Circle());whiteCircle.draw();Shape redSquare = new Red(new Square());redSquare.draw();Shape whiteSquare = new White(new Square());whiteSquare.draw();}
}

测试结果:

红色的圆形
白色的圆形
红色的正方形
白色的正方形

总结

装饰者模式主要用于对现有对象添加新的功能,可在一定程度上代替继承关系,实现低耦合关系。与桥接模式类似,都是为了防止类的膨胀而引出的结构型设计模式。而且在思路上,与桥接模式呈现相反的类的依赖关系。

装饰者模式基于OCP原则,不改变原来对象的属性及行为,只做扩展。

它的类结构特点有两个:继承和组合

其中:

继承的目的是为了可以在原来的位置上替代被装饰对象(前提是调用方使用的是父类引用)。

组合(采用构造器传入一个被装饰对象,并在内部维护这个对象属性)的目的是可以在核心对象的基础之上加以装饰,即保留原来的核心对象的特征和行为,只做扩展,不做修改(OCP原则)。

除了更好的实现对象功能的扩展和特性组合,但是如果扩展功能较多,被迫多层装饰,就会使代码变得较为复杂。

Java常用设计模式————装饰者模式相关推荐

  1. 初学Java常用设计模式之——原型模式

    声明:转载请附上原文链接 提示:标题序号从3开始,是照应不同设计模式笔记发布的顺序而定的,比如,第上一篇文章 初学Java常用设计模式之--工厂模式 序号从2开始. 标题后面之所以加上了解,是因为相对 ...

  2. 初学Java常用设计模式之——工厂模式

    声明:转载请附上原文链接 提示:标题序号从2开始,是照应不同设计模式笔记发布的顺序而定的,比如,第上一篇文章 初学Java常用设计模式之--单例模式 序号从1开始 2. 工厂模式(常用) ⼯⼚模式介绍 ...

  3. 常用设计模式——装饰者模式

    前言 上班族大多都有睡懒觉的习惯,每天早上上班时间都很紧张,于是很多人为了多睡一会,就会用方便的方式解决早餐问题.有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么"加码& ...

  4. Java常用设计模式————享元模式

    引言 享元模式,也叫蝇量模式(Flyweight Pattern).运用共享技术有效地支持大量细粒度的对象. 享元模式常用于系统底层开发,解决系统的性能问题.例如数据库连接池,里面都是创建好的连接对象 ...

  5. Java常用设计模式————抽象工厂模式

    简介 每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例. 与工厂方法模式的区别 工厂方法模式针对的是一个产品等级结构,而抽象工厂模式针对的是多个产品等级结构,因此抽象工厂模式在结构上要比工厂方 ...

  6. 初学Java常用设计模式之——装饰器模式

    声明:转载请附上原文链接 提示:标题序号从8开始,是照应不同设计模式笔记发布的顺序而定的,比如,上一篇文章 初学Java常用设计模式之--桥接模式和组合模式 序号从7开始. 8. 装饰器设计模式(重点 ...

  7. Java常用设计模式————原型模式(一)

    介绍 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象. 原型模式用于创建重复的对象,同时又能保证性能.当直接创建对象的代价比较大时,则采用 ...

  8. Java常用设计模式(一)

      当代软件开发中,设计模式已经成为一种标准的编程实践.在Java编程中,设计模式也同样重要.Java设计模式是软件开发中广泛应用的一种编程方法,它可以帮助开发人员更快地编写出高效.可靠和可维护的代码 ...

  9. 设计模式——装饰者模式

    本文是阅读 Head First 设计模式--装饰者模式的总结. 这本书的教学模式很不错,个人很喜欢,由实际的案例由浅入深,循序渐进的让你明白良好的设计是多么的优雅迷人(回头看看自己的代码,WTF!) ...

最新文章

  1. 关于MySQLdb连接数据的使用(插入数据,删除数据,更新数据,搜索数据——前端页面完成这些对数据库的操作)
  2. 2017.9.6数学
  3. 如何连接oracle xe_为什么应始终将连接池与Oracle XE一起使用
  4. Fritzing添加新的元件库的方法
  5. [知识库:python-tornado]异步调用中的上下文控制Tornado stack context
  6. 地理人必备的宝藏网站
  7. 遇到数学公式中不认识的符号怎么办
  8. 学生上课睡觉班主任怎么处理_学生上课睡觉,老师该怎么处理?
  9. 【Xbox one S】开箱开机初入坑心得
  10. 《近匠》专访Ayla Networks云平台工程部主管——企业级物联网云平台的设计与部署...
  11. 痛心,拼多多一程序员在家跳楼自杀!发生了什么?
  12. mysql常用的tamper脚本_总结一些sqlmap的常用tamper脚本释义
  13. 卓聚社区,新发现的全能社区
  14. java获取视频封面图片
  15. python写api接口实战
  16. 计算机视觉需要学习哪些编程语言?
  17. oracle reorg的意义,Oracle Reorg 的形式与相关的script - 2016-02-26
  18. 海量数据处理问题汇总
  19. 计算机键盘音乐好汉歌,好汉歌(刘欢演唱的歌曲)_百度百科
  20. OpenVINO示例介绍

热门文章

  1. Python通过snmp获取交换机VLAN号、VLAN默认网关、VLAN子网掩码和ARP表中的IP地址与MAC对应记录数据
  2. 2021最新Python量化A股投资必赚策略
  3. oracle不能访问管理页面,Oracle Grid Control CONSOLE无法打开9i数据库的管理维护页面...
  4. wav文件头损坏_Dex文件结构学习
  5. html5群组选择器,css选择器
  6. 小米手机硬改技术_小米11手机爆料:首发骁龙875 或采用屏下摄像头技术
  7. 前端图片上坐标连线_前端图形学(十三)——弹跳运动的深入之傲娇的小球
  8. Foxmail记事插入的表格怎么设置单元格边距
  9. Win11系统无法安装GPT分区的解决方法
  10. Win11正版和盗版有什么区别