设计模式之装饰器模式

news2024/9/22 3:59:58

decorator design pattern

装饰模式的概念、装饰模式的结构、装饰模式的优缺点、装饰模式的使用场景、装饰模式与代理模式的区别、装饰模式的实现示例、装饰模式的源码分析


1、装饰模式的概念

  装饰模式,即在不改变现有对象结构的前提下,动态的给对象增加一些职责(即增加其额外功能)的模式。

2、装饰模式的结构

  • 抽象组件角色:即被装饰对象的抽象角色,定义被装饰对象的行为属性。
  • 具体组件角色:即被装饰的具体对象,继承抽象组件角色,实现其具体的对象行为。
  • 装饰器角色:继承抽象组件角色,引用抽象组件角色。
  • 具体装饰器角色:继承装饰器角色,实现其具体的装饰行为。

decorator-class

3、装饰模式的优缺点

  • 优点:
    • 装饰类和被装饰类可以独立发展,互不耦合。
    • 代替继承模式,动态扩展一个类的功能。
  • 缺点:
    • 多层装饰比较复杂。

4、装饰模式的使用场景

  • 当不能采用继承的方式扩展系统或采用继承的方式扩展系统不利于系统维护时。

    不能采用继承的情况主要有两类:

    • 系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使系统类爆炸。
    • 类定义不能被继承。
  • 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责。

  • 当对象的功能要求可以动态增加、撤销时。

5、装饰模式与代理模式的区别

  装饰模式与静态代理模式的区别:

  • 相同点:
    • 都要实现与目标类相同的业务接口。如装饰模式中的抽象组件角色,静态代理模式中的抽象目标。
    • 在两个类中都要生命目标对象,即对目标对象的引用。
    • 都可以在不修改目标类的前提下增强目标类。
  • 不同点:
    • 目的不同,装饰模式的目的是增强目标对象,代理模式的目的是保护目标对象。
    • 获取目标对象的方式不同,装饰是由外界传递进来或通过构造方法获取的;代理模式是直接在代理类内部创建的,以此来隐藏目标对象。

6、装饰模式的实现示例

抽象组件角色:

public abstract class FastFood {

    private String name;

    private Float price;

    public FastFood() {}

    public FastFood(String name, Float price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Float getPrice() {
        return price;
    }

    public void setPrice(Float price) {
        this.price = price;
    }

    public abstract Float cost();

    @Override
    public String toString() {
        return "FastFood{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

具体组件角色一:

public class NoodlesFastFood extends FastFood {

    public NoodlesFastFood() {
        super("面条", 12f);
    }

    @Override
    public Float cost() {
        return getPrice();
    }
}

具体组件角色二:

public class RiceFastFood extends FastFood {

    public  RiceFastFood() {
        super("米饭", 10f);
    }

    @Override
    public Float cost() {
        return getPrice();
    }
}

装饰器:

public abstract class Decorator extends FastFood {

    private FastFood fastFood;

    public Decorator(FastFood fastFood, String name, Float price) {
        super(name, price);
        this.fastFood = fastFood;
    }

    public FastFood getFastFood() {
        return fastFood;
    }

    public void setFastFood(FastFood fastFood) {
        this.fastFood = fastFood;
    }
}

具体装饰器一:

public class MeatDecorator extends Decorator {

    public MeatDecorator(FastFood fastFood) {
        super(fastFood, "肉", 8f);
    }

    @Override
    public Float cost() {
        setPrice(this.getFastFood().getPrice() + this.getPrice());
        setName(this.getFastFood().getName() + this.getName());
        return this.getPrice();
    }
}

具体装饰器二:

public class VegetableDecorator extends Decorator {

    public VegetableDecorator(FastFood fastFood) {
        super(fastFood, "蔬菜", 2f);
    }

    @Override
    public Float cost() {
        setPrice(this.getFastFood().getPrice() + this.getPrice());
        setName(this.getFastFood().getName() + this.getName());
        return this.getPrice();
    }
}

测试:

public class DecoratorTest {

    public static void main(String[] args) {
        FastFood fastFood = new NoodlesFastFood();
        fastFood.cost();
        System.out.println(fastFood);

        fastFood = new MeatDecorator(fastFood);
        fastFood.cost();
        System.out.println(fastFood);

        fastFood = new VegetableDecorator(fastFood);
        fastFood.cost();
        System.out.println(fastFood);
    }
}

测试结果:

FastFood{name='面条', price=12.0}
FastFood{name='面条肉', price=20.0}
FastFood{name='面条肉蔬菜', price=22.0}

7、装饰模式的源码分析

  jdk 的 io 设计中就用到了装饰模式。

decorator-id-class

  inputStream 作为抽象组件角色,其有多种扩展的具体组件角色,负责从不同的数据源输入,如从字节数组输入、从文件输入、从 String 对象产生输入等;同时其子类 FilterInputStream 为装饰器,且也有多个具体的装饰器实现,在这些装饰中都加入了缓冲的功能,避免每次读取时都进行实际的写操作。所以在此应用中给被装饰对象增加的职能就是缓冲的作用。

  io 中的其它设计如 OutputStream、Writer、Reader 等都是用了装饰模式。

public static void main(String[] args) throws Exception{
  	// fw 即被装饰的对象
    FileWriter fw = new FileWriter("/Users/xgllhz/Documents/project/local/test/test.txt");
  	// bw 即装饰器对象
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write("hello world");
    bw.close();
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【云原生】Grafana 介绍与实战操作

文章目录一、概述二、Grafana 安装1)下载安装2)安装包信息3)启动服务4)Grafana 访问三、Grafana 功能介绍四、使用mysql存储1)安装mysql2)修改grafana配置1、创建grafana用户和grafana库2、修改grafana配置…

[附源码]Python计算机毕业设计Django学分制环境下本科生学业预警帮扶系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

Innodb存储引擎-索引和算法(B+树索引、Cardinality、联合索引、覆盖索引、MRR优化、ICP优化、哈希索引、全文索引)

文章目录索引和算法B树索引聚集索引辅助索引B 树索引的分裂B 树索引的管理Cardinality 值B 树索引的使用联合索引覆盖索引优化器选择不使用索引的情况索引提示Multi-Range Read 优化(MRR)Index Condition Pushdown优化(ICP)哈希索引全文索引倒排索引InnoDB全文检索的实现全文检…

第一个MyBatis查询

⭐️前言⭐️ 在连接程序与数据库的工具中,我们之前使用的是JDBC技术,但是JDBC的操作流程极为繁琐,因此才有了更优秀框架——MyBatis,下边我们一起来看这个优秀框架MyBatis的操作与使用。 🍉欢迎点赞 👍 收…

Innodb存储引擎-锁(数据库锁的查看、快照读当前读、MVCC、自增长与锁、外键与锁、行锁、并发事务的问题、阻塞、死锁、锁升级、锁的实现)

文章目录锁lock 与latch读锁/写锁/意向锁INNODB_TRX/INNODB_LOCKS/INNODB_LOCK_WAITS一致性非锁定读(快照读)一致性锁定读(当前读)MVCC版本链Read View流程自增长与锁外键和锁行锁类型记录锁(record lock)间隙锁(gap lock)下一键锁(next-key lock)并发事务带来的问题阻塞死锁锁…

数据挖掘Java——DBSCAN算法的实现

一、DBSCAN算法的前置知识 DBSCAN算法:如果一个点q的区域内包含多于MinPts个对象,则创建一个q作为核心对象的簇。然后,反复地寻找从这些核心对象直接密度可达的对象,把一些密度可达簇进行合并。当没有新的点可以被添加到任何簇时…

7.加载properties属性文件

一、加载properties属性文件 目的:将数据库的连接参数抽取到一个单独的文件中,与Spring配置文件解耦 1. 编写jdbc.properties属性文件 jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://127.0.0.1:3306/spring_db jdbc.usernameroot jdbc.passwo…

基于萤火虫算法改进的DELM预测-附代码

萤火虫算法改进的深度极限学习机DELM的回归预测 文章目录萤火虫算法改进的深度极限学习机DELM的回归预测1.ELM原理2.深度极限学习机(DELM)原理3.萤火虫算法4.萤火虫算法改进DELM5.实验结果6.参考文献7.Matlab代码1.ELM原理 ELM基础原理请参考&#xff1…

代码中的坏味道

学习笔记自https://zhuanlan.zhihu.com/p/141435233 识别代码中的坏味道系列 如下图是工作中常见的代码的坏味道: 上图中的坏味道出自《重构》这本书,虽然并不是全部,但是涵盖了日常中最常见的一些代码坏味道。 接触这些坏代码可以分为三类&…

【Linux】shell 及权限理解

​🌠 作者:阿亮joy. 🎆专栏:《学会Linux》 🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根 目录👉shell命令…

计算机基础学习笔记:操作系统篇之硬件结构,存储层次结构

二、存储器的层次结构 本文知识来源小林Coding阅读整理思考,原文链接请见该篇文章 存储层次 寄存器高速缓存,Cache 1-3级内存磁盘(SSD,HDD) 关键点 各层次的存储的 介质、速度、容量 以及工作层次理解CPU Cache的作…

【Spring]SpringMVC

一、SpringMVC简介 1、什么是MVC MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分 M:Model,模型层。指工程中的JavaBean,作用是处理数据 JavaBean分为两类: 实体类Bean:专门存储业务数据…

【qt Spin Box | Double Spin Box输入小部件函数学习篇】

Spin Box | Double Spin Box输入小部件函数学习篇【1】UI设计布局【2】setMinimum | setMaximum【3】setPrefix | setSuffix【4】setValue【5】setDisplayIntegerBase【6】setSingleStep【7】value【8】举例【1】UI设计布局 【2】setMinimum | setMaximum setMinimum 此属性保持…

点对点网络与广播式网络的区别

目录 一、点对点网络与广播式网络的区别 二、结点和节点 一、点对点网络与广播式网络的区别 写下本文的原因是笔者在学习计算机网络第一章时看到了下面王道书上的一句话,我不理解这句话想表达的是谁需要“分组存储转发和路由选择机制”。于是当时得出了一个错误…

Python读取excel内容追加到mysql表中赋予字段注释

前言 由于最近遇到一个实体类有特别多的字段,我就想自己一个地在表中创建,并写注释未免太浪费人力和时间了,然后在网上查找资料,果不其然让我看到了一个可以使用Python读取excel内容追加到mysql表中赋予字段注释,这简…

前端零碎知识随笔

一、介绍 本篇博客主要使用来记录一些比较零碎的知识点,都是本人在日常开发工作中遇到的,或者是在学习过程中遇到的。因为这些知识点都比较零碎,为了防止遗忘,所以特意写一篇博客来记录,后面也不会不断慢慢更新的。 …

[附源码]计算机毕业设计Python-大学生健康档案管理(程序+源码+LW文档)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等…

JSP+MySQL基于ssm的环保数据自动采集及预测系统

在21世纪的今天,随着科技的进步和发展,人们的生活逐渐趋于自动化、便捷化、数据化。而发展总会有代价,科技的进步总是伴随着环境的恶化。人类用智慧将地球的资源充分利用,以便丰富人们的生活,推动国家的进步。回过头去看,地球的环境已经成为威胁人类长久生存的主要问题之一。在…

34-Vue之ECharts高级-调色盘

ECharts高级-调色盘前言调色盘主题调色盘全局调色盘局部调色盘渐变颜色前言 本篇来学习下ECharts中调色盘的使用 调色盘 它是一组颜色,图形、系列会自动从其中选择颜色, 不断的循环从头取到尾, 再从头取到尾, 如此往复主要分三种:主题调色盘、全局调色…

基于GDAL的gdb格式数据读写功能实现

一、GDAL类库下载: 下载地址:GISInternals Support Site 比如我下载的是release-1930-x64-gdal-3-4-2-mapserver-7-6-4 点击release-1930-x64-gdal-3-4-2-mapserver-7-6-4的链接,下载这两个文件 二、解压文件和安装gdb插件 1.下载好的两个…