zl程序教程

您现在的位置是:首页 >  后端

当前栏目

设计模式-装饰器模式

2023-06-13 09:13:51 时间

概念

Wrapper装饰器,又称Decorator,是继承关系的一种替代方案;

顾名思义,封装一下,修饰一下

目的:为对象增加不同侧面的特性

装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

image.png
image.png

特点

● Component抽象构件

Component是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。

注意在装饰模式中,必然有一个最基本、最核心、最原始的接口或抽象类充当Component抽象构件。

● ConcreteComponent 具体构件

ConcreteComponent是最核心、最原始、最基本的接口或抽象类的实现,你要装饰的就是它。

● Decorator装饰角色

一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方法,在它的属性里必然有一个private变量指向Component抽象构件。

● 具体装饰角色

ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成其他东西。

简单举例

public interface Component {
    void method();  
}
public class ConcreteComponent implements Component{
    public void method() {
        System.out.println("原来的方法");
    }
}
public abstract class Decorator implements Component{
    protected Component component;
    public Decorator(Component component) {
        super();
        this.component = component;
    }
    public void method() {
        component.method();
    }    
}
public class ConcreteDecoratorA extends Decorator{
    public ConcreteDecoratorA(Component component) {
        super(component);
    }
    public void methodA(){
        System.out.println("被装饰器A扩展的功能");
    }
    public void method(){
        System.out.println("针对该方法加一层A包装");
        super.method();
        System.out.println("A包装结束");
    }
}

实现案例

场景

系统使用A工具生成a报表,发给客户看,定义AReport类完成报表生成;

需求变更:增加B工具生成b报表。定义BReport类完成相应报表生成

定义report接口,AReport和BReport都会实现热report接口,客户端统一调用;

需求变更:工具发给客户端(PDF)同时,导出一个可编辑的word。可以定义 AReportPDF, AReportWord, BReportPDF,BReportWord四个工具类实现相应功能;

需求变更:发给客户端的同时,将报表存在文件服务器FS上。氪定义 AReportPDF2FS, AReportWord2FS, BReportPDF2FS,BReportWord2FS;

需求变更:又增加了一种报表c

可以看到:每次增加需求,不断定义新的工具类。

  • 发送3种报表,所终文件格式生成,发送到FS或者email

定义报表Report接口

image.png

3个具体报表类分别实现Report接口

报表工具类

image.png
image.png
image.png

定义Report的装饰父类

每个Report工具类都可以增加装饰功能

生成有更多 特性的Report工具类

image.png

装饰类1继承Wrapper:实现输出word报告

继承了装饰器;

传入的是具体的某个Report类,为其增加了一些新的功能。

image.png

装饰类2继承Wrapper:实现输出Excel报告装饰类

image.png

装饰类3继承Wrapper: 存储到FTP服务器装饰类

image.png

动态调用

image.png

输出结果

Generate Report using Crystal Report! Export to Word Format! Export to Excel Format! Storage Report to FTP Server!

发送通知消息装饰类

image.png

发送消息到Email装饰类

image.png

调用测试

image.png

结果

Generate Report using Crystal Report! Export to Word Format! Export to Excel Format! Storage Report to FTP Server! Send Report! send to Email!

理解

增加的额外功能可以通过装饰的方式,将其实现;

为一类A增加一个额外功能B,将A抽象成一个接口,有若干的具体类实现A接口

可以A定义一个装饰器父类实现A接口,这类的具体实现类都可以被装饰器装饰;装饰器父类做的就是在构造函数中生成一个功能更丰富的A。

之后所有继承装饰器父类的子装饰器,都是具体增加功能的实现。

优点

  1. 装饰模式与继承关系的目的都是要扩展原有对象的功能,但是装饰器模式比继承增加了更多的灵活性
  2. 使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出更多的不同行为的组合,原有的代码无需改变,符合“开闭”原则
  3. 装饰模式允许系统动态的决定贴上一个需要的装饰,或者除掉一个不需要的装饰。继承关系则不同,继承关系是静态的,他在系统运行前就已经决定了。

缺点

装饰器模式添加了许多子类,过多使用会使程序变得很复杂

增加了系统的复杂程度,加大了使用者的学习成本和理解难度

JAVA IO中的装饰器模式

输入输出流架构

image.png

装饰

● 抽象构件(Component)角色:由OutputStream扮演。这是一个抽象类,为各种子类型提供统一的接口。

● 具体构件(ConcreteComponent)角色:由ByteArrayOutputStream、FileOutputStream、ObjectOutputStream、PipedOutputStream等类扮演。它们实现了抽象构件角色所规定的接口。

● 抽象装饰(Decorator)角色:由FilterOutputStream扮演。它实现了OutputStream所规定的接口。

● 具体装饰(ConcreteDecorator)角色:由几个类扮演,分别是BufferedOutputStream、DataOutputStream等类扮演。

读写架构

image.png

装饰

● 抽象构件(Component)角色:由Writer扮演。这是一个抽象类,为各种子类型提供统一的接口。

● 具体构件(ConcreteComponent)角色:由BufferedWriter、CharArrayWriter、FilterWriter、OutputStreamWriter、PipedWriter、PrintWriter、StringWriter扮演。它们实现了抽象构件角色所规定的接口。

● 抽象装饰(Decorator)角色:由OutputStreamWriter扮演。它实现了Writer所规定的接口。

● 具体装饰(ConcreteDecorator)角色:由FileWriter扮演。