设计模式之装饰器模式(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 关键字修饰的类,或者系统中存在大量通过

继承产生的子类。

相关推荐
BD_Marathon2 小时前
设计模式——合成复用原则
设计模式·合成复用原则
书院门前细致的苹果13 小时前
设计模式大全:单例、工厂模式、策略模式、责任链模式
设计模式·责任链模式·策略模式
BD_Marathon1 天前
设计模式——依赖倒转原则
java·开发语言·设计模式
BD_Marathon1 天前
设计模式——里氏替换原则
java·设计模式·里氏替换原则
jmxwzy1 天前
设计模式总结
设计模式
J_liaty2 天前
23种设计模式一代理模式
设计模式·代理模式
苏渡苇2 天前
优雅应对异常,从“try-catch堆砌”到“设计驱动”
java·后端·设计模式·学习方法·责任链模式
短剑重铸之日2 天前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
feasibility.2 天前
AI 编程助手进阶指南:从 Claude Code 到 OpenCode 的工程化经验总结
人工智能·经验分享·设计模式·自动化·agi·skills·opencode
BD_Marathon2 天前
七大设计原则介绍
设计模式