设计模式之装饰器模式(Decorator)

一、装饰器模式介绍

装饰模式(decorator pattern) 的原始定义是:动态的给一个对象添加一些额外的职责。

就扩展功能而言,装饰器模式提供了一种比使用子类更加灵活的替代方案。

在软件设计中,装饰器模式是一种用于替代继承的技术,它通过一种无须定义子类的方式

给对象动态的增加职责,使用对象之间的关联关系取代类之间的继承关系。

二、装饰器模式原理

装饰器模式结构类图如下所示:

装饰(Decorator)模式中的角色:

1)抽象构件(Component)角色 :它是具体构件和抽象装饰类的共同父类,声明了

在具体构件中实现的业务方法。它引进了可以使客户端以一致的方式处理未被装

饰的对象以及装饰之后的对象,实现客户端的透明操作

2)具体构件(Concrete Component)角色 :它是抽象构件类的子类,用于定义具体

的构建对象,实现了在抽象构建中声明的方法,装饰类可以给它增加额外的职责

(方法)。即被装饰者

3)抽象装饰(Decorator)角色 :它也是抽象构件类的子类,用于给具体构件增加

职责,但是具体职责在其子类中实现。它维护了一个指向抽象构件对象的引用,

通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达

到装饰的目的。

4)具体装饰(ConcreteDecorator)角色 : 它是抽象装饰类的子类,负责向构件添加

新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中

定义的方法,并可以增加新的方法用于扩充对象的行为。

装饰者模式中的各个角色用代码表示如下:

java 复制代码
/*******************************************************
 * 抽象构建类(抽象构件),
 * 抽象构建类可以是抽象类,也可以是接口
 *
 *******************************************************/
public abstract class Component {

    //抽象方法
    public abstract void operation();
}

/*******************************************************
 * 具体构建类(被装饰类)
 *
 *******************************************************/
public class ConcreteComponent extends Component{

    @Override
    public void operation() {
        //基础功能实现(复杂功能通过装饰类进行扩展)
    }
}


/*******************************************************
 * 抽象装饰类--装饰者模式的核心
 *
 *******************************************************/
public class Decorator extends Component{

    //维持一个对抽象构件对象的引用
    private Component component;

    //注入一个抽象构件类型的对象
    public Decorator(Component component) {
        this.component = component;
    }


    @Override
    public void operation() {
        //调用原有业务方法(这里并没有真正实施装饰,而是提供了一个统一的接口,将装饰过程交给子类完成)
        component.operation();
    }
}


/*******************************************************
 * 具体装饰类
 *
 *******************************************************/
public class ConcreteDecorator extends Decorator{


    public ConcreteDecorator(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation(); //调用原有业务方法
        addedBehavior(); //调用新增业务方法
    }

    //新增业务方法
    public void addedBehavior(){
        //......
    }
}

三、装饰器模式应用示例

以文件读写器程序为例, 演示一下装饰者模式的使用,该示例主要类如下:

1)DataLoader:抽象的文件读取接口DataLoader ;抽象构件角色

2)BaseFileDataLoader:具体组件BaseFileDataLoader,重写组件 DataLoader

的读写方法;具体构件角色

3)DataLoaderDecorator:装饰器DataLoaderDecorator,这里要包含一个引用

DataLoader 的对象实例 wrapper,同样是重写 DataLoader 方法,不过这里

使用 wrapper 来读写,并不进行扩展;抽象装饰者

4)EncryptionDataDecorator:读写时有加解密功能的具体装饰器

EncryptionDataDecorator,它继承了装饰器 DataLoaderDecorator 重写读写方法;

具体装饰者

该示例的UML类图如下:

该示例具体代码如下:

java 复制代码
/**
 * 我们以一个文件读写器程序为例, 演示一下装饰者模式的使用
 *
 * 抽象的文件读取接口DataLoader--抽象构建类
 */
public interface DataLoader {
    //读
    String read();
    //写
    void write(String data);
}



*******************************************************
 * 具体组件,重写方法 -- 具体构建类(被装饰类)
 *
 *******************************************************/
public class BaseFileDataLoader implements DataLoader{

    //读取/写入 的文件路径
    private String filePath;

    public BaseFileDataLoader(String filePath) {
        this.filePath = filePath;
    }

    @Override
    public String read() {

        try {
            String result = FileUtils.readFileToString(new File(filePath), "utf-8");
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void write(String data) {
        try{
            FileUtils.writeStringToFile(new File(filePath), data, "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}




/*******************************************************
 * 抽象装饰者类
 *
 * 
 *******************************************************/
public class DataLoaderDecorator implements DataLoader{

    //抽象构建类的引用
    private DataLoader wrapper;

    public DataLoaderDecorator(DataLoader wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public String read() {
        return wrapper.read();
    }

    @Override
    public void write(String data) {
        wrapper.write(data);
    }
}




/*******************************************************
 * 具体装饰者类--对读取/写入数据 进行加解密
 * 
 *******************************************************/
public class EncryptionDataDecorator extends DataLoaderDecorator{

    public EncryptionDataDecorator(DataLoader wrapper) {
        super(wrapper);
    }

    //重写 抽象构建类的 读/写 方法
    @Override
    public String read() {
        return decode(super.read());
    }

    @Override
    public void write(String data) {
        super.write(encode(data));
    }


    //加密操作
    private String encode(String data) {
        try {
            Base64.Encoder encoder = Base64.getEncoder();
            byte[] bytes = data.getBytes("UTF-8");
            String result = encoder.encodeToString(bytes);

            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //解密
    private String decode(String data) {

        try {
            Base64.Decoder decoder = Base64.getDecoder();
            String result = new String(decoder.decode(data), "UTF-8");
            return result;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}


//测试
public class Test {

    public static void main(String[] args) {

        String info = "name:tom java";
        DataLoaderDecorator decorator = new EncryptionDataDecorator(new BaseFileDataLoader("demo.txt"));
        decorator.write(info);

        String data = decorator.read();
        System.out.println(data);
    }
}

四、装饰器模式总结

1、装饰者模式优点

1)对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加

2)可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不

同的具体装饰类,从而实现不同的行为

3)可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列

组合可以创造出很多不同行为的组合,得到更加强大的对象

4)具体构建类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构建类和

具体装饰类,原有类库代码无序改变,符合开闭原则

2、装饰者模式缺点

1)在使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相

互连接的方式有所不同,而不是它们的类或者属性值不同,大量的小对象的产生势必会

占用更多的系统资源,在一定程度上影响程序的性能

2)装饰器模式提供了一种比继承更加灵活、机动的解决方案,但同时也意味着比继承更

加易于出错,排错也更加困难,对于多次装饰的对象,在调试寻找错误时可能需要逐级

排查,较为烦琐

3、装饰者模式适用场景

1)快速动态扩展和撤销一个类的功能场景。 比如,有的场景下对 API 接口的安全性要求较

高,那么就可以使用装饰模式对传输的字符串数据进行压缩或加密。如果安全性要求不

高,则可以不使用。

2)不支持继承扩展类的场景。 比如,使用 final 关键字修饰的类,或者系统中存在大量通过

继承产生的子类。

相关推荐
CocoaAndYy2 小时前
设计模式-适配器模式
设计模式·适配器模式
刷帅耍帅2 小时前
设计模式-适配器模式
设计模式·适配器模式
拥有一颗学徒的心4 小时前
设计模式——命令模式
设计模式·命令模式
拉里小猪的迷弟7 小时前
设计模式-结构型-常用:代理模式、桥接模式、装饰者模式、适配器模式
设计模式·代理模式·桥接模式·适配器模式·装饰器模式
CocoaAndYy9 小时前
设计模式-单例模式
单例模式·设计模式
bobostudio199511 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
ok!ko15 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
拉里小猪的迷弟16 小时前
设计模式-创建型-常用:单例模式、工厂模式、建造者模式
单例模式·设计模式·建造者模式·工厂模式
严文文-Chris18 小时前
【设计模式-中介者模式】
设计模式·中介者模式