JAVA装饰器模式详解

装饰器模式

1 装饰器模式介绍

装饰模式(decorator pattern) 的原始定义是:动态的给一个对象添加一些额外的职责. 就扩展功能而言,装饰器模式提供了一种比使用子类更加灵活的替代方案.

假设现在有有一块蛋糕,如果只有涂上奶油那这个蛋糕就是普通的奶油蛋糕, 这时如果我们添加上一些蓝莓,那这个蛋糕就是蓝莓蛋糕.如果我们再拿一块黑巧克力 然后写上姓名、插上代表年龄的蜡烛, 这就是变成了一块生日蛋糕

在这里插入图片描述

在软件设计中,装饰器模式是一种用于替代继承的技术,它通过一种无须定义子类的方式给对象动态的增加职责,使用对象之间的关联关系取代类之间的继承关系.

2 装饰器模式原理

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

  • 抽象构件(Component)角色 :它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法.它引进了可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作
  • 具体构件(Concrete Component)角色 :它是抽象构件类的子类,用于定义具体的构建对象,实现了在抽象构建中声明的方法,装饰类可以给它增加额外的职责(方法).
  • 抽象装饰(Decorator)角色 :它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现.它维护了一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的.
  • 具体装饰(ConcreteDecorator)角色 : 它是抽象装饰类的子类,负责向构件添加新的职责.每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用于扩充对象的行为.

在这里插入图片描述

代码如下

/**
 * 抽象构件类
 **/
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(){
        //......
    }
}

3 装饰器模式应用实例

我们以一个文件读写器程序为例, 演示一下装饰者模式的使用,下面是该程序的UML类图

在这里插入图片描述

  • DataLoader
    • 抽象的文件读取接口DataLoader
  • BaseFileDataLoader
    • 具体组件BaseFileDataLoader,重写组件 DataLoader 的读写方法
  • DataLoaderDecorator
    • 装饰器DataLoaderDecorator,这里要包含一个引用 DataLoader 的对象实例 wrapper,同样是重写 DataLoader 方法,不过这里使用 wrapper 来读写,并不进行扩展
  • EncryptionDataDecorator
    • 读写时有加解密功能的具体装饰器EncryptionDataDecorator,它继承了装饰器 DataLoaderDecorator 重写读写方法

导入IO工具类

    <dependencies>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

1 ) DataLoader

/**
 * 抽象的文件读取接口DataLoader
 **/
public interface DataLoader {

    String read();

    void write(String data);
}

2 ) BaseFileDataLoader

/**
 * 具体组件,重写读写方法
 **/
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();
        }
    }
}

3 ) DataLoaderDecorator

/**
 * 装抽象饰者类
 **/
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);
    }
}

4 ) EncryptionDataDecorator

/**
 * 具体装饰者-对文件内容进行加密和解密
 **/
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;
        }
    }

}

5 ) 测试

public class TestDecorator {

    public static void main(String[] args) {

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

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

4 装饰器模式总结

装饰器模式的优点:

  1. 对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加
  2. 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为.
  3. 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合可以创造出很多不同行为的组合,得到更加强大的对象.
  4. 具体构建类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构建类和具体装饰类,原有类库代码无序改变,符合开闭原则.

装饰器模式的缺点:

  1. 在使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值不同,大量的小对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能.
  2. 装饰器模式提供了一种比继承更加灵活、机动的解决方案,但同时也意味着比继承更加易于出错,排错也更加困难,对于多次装饰的对象,在调试寻找错误时可能需要逐级排查,较为烦琐.

装饰器模式的适用场景

  1. 快速动态扩展和撤销一个类的功能场景。 比如,有的场景下对 API 接口的安全性要求较高,那么就可以使用装饰模式对传输的字符串数据进行压缩或加密。如果安全性要求不高,则可以不使用。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/375725.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[职场] 智能材料与结构专业的就业前景 #经验分享#学习方法

智能材料与结构专业的就业前景 智能材料与结构专业是面向国家智能制造强国战略&#xff0c;面向地方经济新旧动能转换需求&#xff0c;学习智能材料与结构的基础理论及基本知识&#xff0c;接受智能材料制备、组织分析、性能测试、智能材料系统集成技能的基本训练&#xff0c;…

蓝桥杯省赛无忧 课件127 线段树维护哈希

01 问题引入 02 算法思路 03 代码实现 04 例题讲解

Linux中共享内存(mmap函数的使用)

内存映射的基本使用 内存映射 概念&#xff1a; 使一个磁盘文件与内存中的一个缓冲区相映射&#xff0c;进程可以像访问普通内存一样对文件进行访问&#xff0c;不必再调用read,write。 mmap()的优点&#xff1a; 实现了用户空间和内核空间的高效交互方式 优化前&#xff1a;优…

时序数据库Influxdb查询多个字段_field同一时间的值,组成一条数据

Influxdb将表格数据多个字段_field从垂直列布局聚合成水平布局行字段。 问题 1、Influxdb 是一种时间序列数据库&#xff0c;在我的项目中主要用来存储换热站的测点数据的。换热站有非常多的测点&#xff0c;我们用Flux 语法去查询测点数据&#xff0c;返回的数据结构是每个测…

【MySQL进阶之路】MySQL生产环境部署该如何选择机器配置?

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

酷开科技,打造非凡的生活体验

酷开科技&#xff0c;作为一家专注于智能电视操作系统研发及智能电视运营增值服务的高科技企业&#xff0c;始终致力于为消费者提供非凡的生活体验。通过不断创新的技术和产品&#xff0c;酷开科技为消费者们带来了便捷、舒适、个性化的智能生活。 首先&#xff0c;酷开科技在智…

阿里云游戏服务器收费价格表,一年和1个月报价

阿里云游戏服务器租用价格表&#xff1a;4核16G服务器26元1个月、146元半年&#xff0c;游戏专业服务器8核32G配置90元一个月、271元3个月&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云游戏专用服务器详细配置和精准报价&#xff1a; 阿里云游戏服务器租用价格表 阿…

【 buuctf-数据包中的线索】

这题比较简单&#xff0c;只要能想到base64 转图片 复制此处密文&#xff0c;发现 base64 正常解码解不出来&#xff0c;就要想到可能是图片 需要注意&#xff0c;/9j是jpg文件头的 base64 编码 BUUCTF的wireshark流量分析题目writeup汇总_ctf wireshark练习题-CSDN博客&#…

蓝桥杯刷题day07——斐波那契与7

1、题目描述 斐波那契数列的递推公式为:FnFn-1Fn-2, 其中F1F21. 请问, 斐波那契数列的第 1 至 202202011200 项&#xff08;含&#xff09;中, 有多少项的个位 是 7 。 答案提交 这是一道结果填空的题, 你只需要算出结果后提交即可。本题的结果为一 个整数, 在提交答案时只填…

Maven构建OSGI+HttpServer应用

Maven构建OSGIHttpServer应用 官网&#xff08;https://eclipse.dev/equinox/server/http_in_equinox.php&#xff09;介绍有两种方式&#xff1a; 一种是基于”org.eclipse.equinox.http”包的轻量级实现&#xff0c;另一种是基于”org.eclipse.equinox.http.jetty”包&#…

2024最新CleanMyMac X优化Mac电脑系统体验分享

使用Mac电脑的用户都希望它们能够保持最佳性能。但有时&#xff0c;你可能会发现你的Mac运行变慢或响应迟缓。这可能是由于几个原因造成的&#xff0c;包括硬盘空间不足、系统缓存堆积、以及过多的启动项等。解决了这些问题&#xff0c;你可以显著提升你的Mac性能。本文将探讨导…

工程示例(LED、流水灯、蜂鸣器)

LED闪烁 #include "stm32f10x.h" // Device header #include "Delay.h"int main(void) {RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitTypeDef GPIO_InitSructure;GPIO_InitSructure.GPIO_Mode GPIO_Mode_Out_PP;GPIO…

SpringBoot+随机盐值+双重MD5实现加密登录

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、salt…

遗失的源代码之回归之路的探索与实践

背景 最近比较突然被安排接手一个项目,该项目的情况如下 原生和RN结合的混合开发模式组件化开发,有很多基础组件以及业务组件但是在梳理项目依赖时发现了个别组件源码不全的情况,于是写了个cli用于对比两个版本产物文件,生成差异结果以便于快速进行源码找回恢复。 结果如下…

Python tkinter (16) —— Progressbar

本文主要介绍Python tkinter 进度条Progressbar应用及示例。 目录 系列文章 进度条Progressbar 基本概念 参数&#xff1a; mode参数 基本应用 动画设计 引入time 具体实现 start/step/stop step(amount)&#xff1a; start(interval)&#xff1a; stop()&#xff…

QT 范例阅读:系统托盘 The System Tray Icon example

main.cpp QApplication app(argc, argv);//判断系统是否支持 系统托盘功能if (!QSystemTrayIcon::isSystemTrayAvailable()) {QMessageBox::critical(0, QObject::tr("Systray"),QObject::tr("I couldnt detect any system tray ""on this system.&qu…

一文掌握SpringBoot注解之@Configuration知识文集(6)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

ionic报错:Cannot read properties of undefined (reading ‘classList‘)

报错信息&#xff1a; [ionic/vue Warning]: The view you are trying to render for path /tabs/tab1 does not have the required <ion-page> component. Transitions and lifecycle methods may not work as expected.See https://ionicframework.com/docs/vue/navig…

fx-82es软升级至fx-991es整理

fx-82es和fx-991es在硬件上采用的是相同的流水线设计。fx-82es为了降低成本或出于其他考虑&#xff0c;卡西欧在其主板上去掉了一些以微积分为主的功能 也就是说fx-82es理论上是有可能升级到fx-991es的&#xff0c;硬件上进行升级之前有人尝试成功过了&#xff0c;但是有一定风…

30s速通String——从JVM内存 到相关方法

0.深度理解String&#xff08;初学者可后面再看&#xff09; 1.JVM理解两种初始化String方式 1.1直接初始化 栈中保存变量s1,s2&#xff0c;而变量保存“abc”在方法区的地址 这里当“abc”具有唯一性&#xff0c;字符串常量区无此字符串&#xff0c;我们就产生一个新内存“…