1 基础知识
1.1 标准定义
装饰器(Decorator)模式标准定义:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。
1.2 分析和说明
装饰器(Decorator)模式属于结构型设计模式。装饰器模式用于动态地为对象附加额外的职责,以达到扩展其功能,是继承关系的一个替代方案,提供比继承更多的灵活性。动态给一个对象增加功能,这些功能可以再动态的撤消。增加由一些基本功能的排列组合而产生的非常大量的功能。
Decorator结构如图1所示,角色包括抽象构件(Component)角色、具体构件(Concrete Component)角色、装饰器(Decorator)角色和具体装饰器(Concrete Decorator)角色。
图1 装饰器模式结构
抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。抽象构件角色作为整个装饰器模式类图体系的超类,其子类均可以被增添附加责任。
具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
装饰器(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
具体装饰器(Concrete Decorator)角色:负责给构件对象增添附加的责任。
2 应用场景举例
比如公司的软件工程都是由需求分析、设计、编码、测试、部署和维护组成。这只是一般过程,但是万一有的时候要加上需求分析验证,有的时候要加上设计验证等过程。就可以通过装饰器模式来实现。软件工程过程是抽象构件角色:标准软件工程过程是具体构件角色:定义一个将要接收附加责任的类。附加验证是装饰器角色。需求分析验证是具体装饰器角色。应用场景的用例见图2。
图2 装饰器模式用例图
在这里可以把AbstractProcess类理解为抽象构件(Component)角色。StandardProcess类是具体构件(Concrete Component)角色。AdditionalProcess类是一种装饰器(Decorator)角色。DesignCheckProcess类和RequestVerificationProcess类是具体装饰器(Concrete Decorator)角色。其实现类图如图3所示。AbstractProcess抽象类有两个子类,一个是StandardProcess类,另一个是AdditionalProcess类。AdditionalProcess类不仅仅继承AbstractProcess抽象类,而且还关联AbstractProcess抽象类。DesignCheckProcess类和RequestVerificationProcess类是继承AdditionalProcess类的子类,他们是附加类的具体实现。
图3 装饰器模式类图
装饰器模式实现如图4所示,实现顺序描述:
①创建一个StandardProcess对象,
②创建一个RequestVerificationProcess对象;
③把RequestVerificationProcess对象赋值给StandardProcess对象;
④调用RequestVerificationProcess对象的ConcreteActualProcess方法;
⑤创建一个DesignCheckProcess对象;
⑥把DesignCheckProcess对象赋值给StandardProcess对象;
⑦调用DesignCheckProcess对象的ConcreteActualProcess方法;
⑧显示StandardProcess对象最新的项目过程情况。
图4 装饰器模式实现顺序图
对于增加项目过程的方式有两种,一种是直接在标准的项目过程中加入项目过程,还有一种是附加项目过程,然后接着在附加项目过程中加入项目过程。第一种方式要修改整个全局项目过程的内容,所以改动比较大,而采用第二种方式,只是修改附加项目过程,只是修改了部分内容。
3.Java的实现程序代码
Java程序实现主要包括AbstractProcess类文件,StandardProcess类文件,AdditionalProcess类文件,DesignCheckProcess类文件和RequestVerificationProcess类文件等5个文件。其关系如图3所示。下面分别列出这5个文件的程序代码,最后列出测试代码并显示输出结果。
AbstractProcess类程序代码清单01所示。
程序代码清单01
public abstract class AbstractProcess { protected List<String> componentList = new ArrayList<String>(); public void addProcess(String processName) { componentList.add(processName); } public void showAllProcess() { if (componentList == null) { System.out.println("没有过程"); } for (int i = 0; i < componentList.size(); i++) { System.out.print(componentList.get(i) + ";"); } } } |
StandardProcess类程序代码清单02所示。
程序代码清单02
public class StandardProcess extends AbstractProcess { public StandardProcess() { initizeProcess(); } private void initizeProcess() { addProcess("需求分析过程"); addProcess("设计过程"); addProcess("编码过程"); addProcess("测试过程"); addProcess("部署过程"); addProcess("维护过程"); } } |
AdditionalProcess类程序代码清单03所示。
程序代码清单03
public class AdditionalProcess extends AbstractProcess { protected AbstractProcess actualProcess; public void setActualProcess(AbstractProcess actualProcess) { this.actualProcess = actualProcess; } } |
DesignCheckProcess类和RequestVerificationProcess类程序代码清单04所示。
程序代码清单04
public class DesignCheckProcess extends AdditionalProcess { public void ConcreteActualProcess() { actualProcess.addProcess("设计检查"); } } public class RequestVerificationProcess extends AdditionalProcess { public void ConcreteActualProcess() { actualProcess.addProcess("需求验证"); } } |
装饰器模式测试程序的代码清单05如下:
程序代码清单05
public class Client { public static void main(String[] args) { AbstractProcess projectProcess = new StandardProcess(); System.out.println("——————项目的标准过程———————"); projectProcess.showAllProcess(); System.out.println(); // 附加需求验证过程 RequestVerificationProcess projectAddProcess1 = new RequestVerificationProcess(); projectAddProcess1.setActualProcess(projectProcess); projectAddProcess1.ConcreteActualProcess(); System.out.println("——————增加需求验证过程后的项目过程———————"); projectProcess.showAllProcess(); System.out.println(); // 附加设计检查过程 DesignCheckProcess projectAddProcess2 = new DesignCheckProcess(); projectAddProcess2.setActualProcess(projectProcess); projectAddProcess2.ConcreteActualProcess(); System.out.println("——————再增加设计检查过程后的项目过程———————"); projectProcess.showAllProcess(); } } |
装饰器模式测试类输出结果如下所示:
——————项目的标准过程——————— 需求分析过程;设计过程;编码过程;测试过程;部署过程;维护过程; ——————增加需求验证过程后的项目过程——————— 需求分析过程;设计过程;编码过程;测试过程;部署过程;维护过程;需求验证; ——————再增加设计检查过程后的项目过程——————— 需求分析过程;设计过程;编码过程;测试过程;部署过程;维护过程;需求验证;设计检查; |
4 扩展和说明
JDK中I/O 库中InputStream实现就是采用Decorator模式。在以Java的I/O系统中的输入流为有多种来源,有ByteArrayInputStream, FileInputStream, FilterInputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBufferInputStream等。其中ByteArrayInputStream对应字节数组,FileInputStream对应文件流,ObjectInputStream对应对象流,PipedInputStream对应管道流,StringBufferInputStream对应String对象流,SequenceInputStream对应流序列,FilterInputStream对应一些要求额外功能的数据处理流。
FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以对直接传输数据或提供一些额外的功能。一方面,FilterInputStream 类本身只是简单地重写那些将所有请求传递给所包含输入流的 InputStream 的所有方法。另一方面,FilterInputStream 的子类可进一步重写这些方法中的一些方法,并且还可以提供一些额外的方法和字段。FilterInputStream 的子类包括BufferedInputStream类(支持缓冲输入和mark和reset方法的能力)、DataInputStream类(数据输入流允许应用程序以与机器无关方式从基础输入流中读取基本 Java 数据类型)、LineNumberInputStream(针对输入流提供跟踪当前行号的附加功能)等。在这里就可以用到Decorator模式。JDK的InputStream类图结构如图5所示。
图5 JDK的InputStream类结构图
FilterInputStream类的程序实现代码如程序代码清单08所示。
程序代码清单08
package java.io; public class FilterInputStream extends InputStream { protected volatile InputStream in; protected FilterInputStream(InputStream inputstream) { in = inputstream; } public int read() throws IOException { return in.read(); } public int read(byte abyte0[]) throws IOException { return read(abyte0, 0, abyte0.length); } public int read(byte abyte0[], int i, int j) throws IOException { return in.read(abyte0, i, j); } public long skip(long l) throws IOException { return in.skip(l); } public int available() throws IOException { return in.available(); } public void close() throws IOException { in.close(); } public synchronized void mark(int i) { in.mark(i); } public synchronized void reset() throws IOException { in.reset(); } public boolean markSupported() { return in.markSupported(); } } |
FilterInputStream继承并关联InputStream。InputStream与装饰的FilterInputStream对象有相同的接口,并且除了接口中给出的方法外,FilterInputStream有自己添加的方法,来添加对象功能。FilterInputStream有一个指向Subject对象的引用,附加的功能被添加在这个InputStream对象上。而FilterInputStream本身也是一个InputStream类,因而它也能够被其他的Decorator所修饰,提供组合的功能。
在Java IO操作中,为增强FilterInputStream功能,可以采用程序代码清单09的写法。
程序代码清单09
thisStringBuffer = new StringBuffer("This is a sample string to be read"); FilterInputStream thisStream= new LineNumberInputStream( new BufferInputStream(new StringBufferInputStream(thisStringBuffer))); thisStream.read(); thisStream.line(); |
多个的Decorator被层叠在一起,最后得到一个功能强大的流。既能够被缓冲,又能够得到行数,这就是Decorator的威力!
参考链接
7种结构型模式:
Gof23种设计模式(6)——适配器模式(Adapter)
Gof23种设计模式(7)——桥接模式(Bridge)
Gof23种设计模式(8)——组合模式(Composite)
Gof23种设计模式(9)——装饰器模式(Decorator)
Gof23种设计模式(10)——外观模式(Facade)
Gof23种设计模式(11)——享元模式(Flyweight)
Gof23种设计模式(12)——代理模式(Proxy)
Gof23种设计模式 —— 结构型模式总结和比较
回到总目录:Gof23种设计模式(全解析)
(转载自微信公众号:架构设计模式)