装饰器模式使你可以在运行时使用类似于对象组成的技术来装饰类. 这在我们希望实例化具有新职责的对象而无需对基础类进行任何代码更改的情况下尤其有用. 本文是在学习完优锐课 JAVA 架构 VIP 课程 -[框架源码专题] 中《学习源码中的优秀设计模式》后写下的学习感悟. 探讨了这种模式, 并向你展示了如何使用提供的 Java 代码示例来实现它.
深入探索 Java 设计模式 (一) 之单例模式
深入探索 Java 设计模式 (二) 之策略模式
总览
装饰器模式是 "四人帮"(Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides)建立的结构设计模式之一. 通过解决在运行时向对象添加新状态或行为的反复出现的问题, 它在面向对象的设计中利用了可重用性和灵活性. 尽管这种想法与面向对象原理 (称为继承) 押韵, 但简单继承在这种情况下不适用, 因为它是静态的并且考虑到整个类. 这为新方法铺平了道路, 因为它着重于提供灵活的替代方法来扩展子类功能, 因此可以动态地向对象施加新的责任.
装饰器模式
顾名思义, 装饰器模式可配置特定对象的功能. 这是 Java 原始 IO 类中的一种常见模式, 用于对 JVM 之外的源进行读写. 例如, InputStream 和 OutputStream 类及其子类在其读取和写入操作中广泛使用此模式. 可以链接这些类的实现, 以有效地从不同的源 (例如本机文件系统) 读取和写入数据.
例如, 请注意抽象类 OutputStream. 它有一个称为 read 的抽象方法, 该方法必须由子类定义. 可以重写该方法以扩展其行为, 以更改或增强其效率. 在将职责委派给另一个 OutputStream 之前, OutputStream 实现会执行所需的工作. 实现链将另一个 OutputStream 用作构造函数参数. 具体的子类, 例如 OutputStream 的 FileOutputStream 或 SocketOutputStream, 是管道的末尾, 最终写入数据, 而没有将写入责任委托给另一个流. 因此, 在其构造函数参数中不需要另一个 OutputStream 对象.
让我们看看在 Java IO 类的 OutputStream 类中使用装饰器模式如何导致在将字节数组写入磁盘之前将多个操作链接在一起.
- @Test
- public void testingDecoratorPattern() throws IOException {
- final File file = new File("myfile.dat");
- final FileOutputStream fileOutputStream = new
- FileOutputStream(f);
- final BufferedOutputStream bufferedOutputStream = new
- BufferedOutputStream(fileOutputStream);
- final ObjectOutputStream objectOutputStream = new
- ObjectOutputStream(fileOutputStream);
- objectOutputStream.writeBoolean(true);
- objectOutputStream.writeInt(12);
- objectOutputStream.writeObject(new ArrayList<Integer>());
- objectOutputStream.flush();
- objectOutputStream.close();
- bufferedOutputStream.close();
- fileOutputStream.close();
- assertTrue(file.exists());
- }
FileOutputStream 对象用于将文件写入磁盘. BufferedOutputStream 对象缓存对写操作的所有调用, 并一次写入几个字节. 这可以提高效率, 特别是在写入磁盘时. ObjectOutputStream 中的对象序列化的内置机制将对象和原始类型写入流中. 但是, ObjectOutputStream 不知道将文件写入何处. 这主要用于将责任委托给另一个 OutputStream.
装饰器模式的使用
假设我们要创建一个类设计, 但要增加新功能. 在这种情况下, 装饰器模式可为客户端提供所需的功能组合, 以增强进一步的实现, 如图 1 所示.
图 1: 装饰器模式
在这里, 茶是一个抽象类, 由产品的所有类别或变体子类化. 在包含有关其类型的特定信息的每个子类中都设置了 detailsinstance 变量. getDetails()方法返回有关其类型的信息. 父类将 price() 方法声明为抽象, 子类将定义其自己的实现. 除了可用的茶类型以外, 我们还可以通过多种变体和组合实现任意数量的茶. 这是装饰器模式的关键.
实现装饰器模式
现在, 让我们看看如何实现装饰器模式. 该示例非常简单, 不言自明. 这些类的布局如下.
- package org.mano.example;
- public interface Car {
- void paint();
- }
- package org.mano.example;
- public class ElectricCar implements Car {
- @Override
- public void paint() {
- // ...
- }
- }
- package org.mano.example;
- public class HybridCar implements Car {
- @Override
- public void paint() {
- // ...
- }
- }
- package org.mano.example;
- public abstract class CarDecorator implements Car {
- protected Car decoratedCar;
- public CarDecorator(Car car){
- decoratedCar = car;
- }
- public void paint(){
- decoratedCar.paint();
- }
- }
- package org.mano.example;
- public class CarColorDecorator extends CarDecorator {
- public CarColorDecorator(Car car) {
- super (car);
- }
- @Override
- public void paint(){
- decoratedCar.paint();
- setTheme(decoratedCar);
- }
- private void setTheme(Car car){
- // ...
- }
- }
- package org.mano.example;
- public class DPApp {
- public static void main(String[] args) {
- Car defaultHybridCar = new HybridCar();
- Car redHybridCar = new CarColorDecorator(new
- HybridCar());
- Car blueElectricCar = new CarColorDecorator(new
- ElectricCar());
- defaultHybridCar.paint();
- redHybridCar.paint();
- blueElectricCar.paint();
- }
- }
结论
这是 OOP 中最常用的模式之一. 这种模式的强大之处在于将对象组合在一起, 例如 ObjectOutputStream,BufferedOutputStream 和 FileOutputStream 扩展了抽象超类 OutputStream. 每个子类构造函数都将 OutputStream 对象作为参数. 没有装饰器模式, 这将是不可能的. 否则, 我们必须创建许多类来获取本质, 这将是一个糟糕的设计.
来源: https://www.cnblogs.com/youruike-/p/12065939.html