JAVA设计模式-装饰者模式

news2024/11/17 21:32:37

一.概念

装饰器模式(Decorator Pattern),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰器模式比生成子类更灵活。 —-《大话设计模式》

允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

二.角色

  • Component(抽象构件):给出一个抽象接口,装饰器模式中公共方法的类,在装饰器模式结构图的顶层,以规范准备接收附加责任的对象。
  • ConcreteComponent(具体构件):是要动态扩展的对象,转换器模式中具体的被装饰的类,它继承自Component。
  • Decorator(装饰器):持有一个构件(Component)对象的实例,它是装饰器模式中的核心对象,所有具体装饰器对象的父类,完成装饰器的部分职能。可以只对被装饰的对象进行一些简单的包裹,也可包含对Component中方法的实现。
  • ConcreteDecorator(具体装饰):完成具体的装饰功能。装饰功能的实现是通过调用被装饰对象对应的方法,加上装饰对象自身的方法。这是装饰器模式动机中的添加额外功能的关键。

三.优缺点

1.优点
  • 装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
  • 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。装饰模式允许系统动态决定“贴上”或者除掉一个“装饰”,继承关系是静态的,它在系统运行前就决定了;
  • 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合;
  • 装饰者类可以在被装饰者的行为前面或后面加上自己的行为,甚至取代被装饰者的行为,达到特定的目的;
  • 装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型
2.缺点
  • 多层装饰比较复杂。
  • 由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

四.适用场景

  • 运行时,你需要动态地为对象增加额外职责时;
  • 当你需要一个能够代替子类的类,借助它提供额外方法时。
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;
  • 处理那些可以撤销的职责;
  • 当不能采用生成子类的方式进行扩充时。

五.装饰器模式与适配器模式的比较

共同点:都拥有一个目标对象。装饰器通过包装一个装饰对象来扩展其功能,而又不改变其接口,这实际上是基于对象的适配器模式的一种变种。
不同点:适配器模式需要实现另外一个接口,而装饰器模式必须实现该对象的接口。适配器模式主要是为了接口的转换,而装饰者模式关注的是通过组合来动态的为被装饰者注入新的功能或行为(即所谓的责任)。

六.实现

假设我去买咖啡,首先服务员给我冲了一杯原味咖啡,我希望服务员给我加些牛奶和白糖混合入原味咖啡中。使用装饰器模式就可以解决这个问题。

咖啡接口

定义了获取花费和配料的接口。

/**
 * 咖啡接口
 */
public interface Coffee {
    /**
     * 获取价格
     * @return
     */
    public float getPrice();

    /**
     * 获取咖啡
     * @return
     */
    public String getCoffee();
}
原味咖啡

实现Coffe接口,花费1元,配料中,只有咖啡

/**
 * 原味咖啡类
 */
public class OriginalCoffee implements Coffee {
    @Override
    public float getPrice() {
        return 1;
    }

    @Override
    public String getCoffee() {
        return "原味咖啡";
    }
}
装饰器类

咖啡对象的装饰器类,同样实现Coffee接口,定义一个Coffe对象的引用,在构造器中进行初始化。并且将getPrice()和getCoffee()方法转发给被装饰对象。

/**
 * 咖啡的"装饰器",可以给咖啡添加各种"配料"
 * 该类是一个抽象类需要具体子类来实现
 */
public class DecoratorAbstractCoffee implements Coffee {
    /**
     * 具体咖啡的接口
     */
    protected final  Coffee coffee;

    /**
     * 构造方法,初始化咖啡对象的引用
     * @param coffee
     */
    public DecoratorAbstractCoffee(Coffee coffee) {
        this.coffee = coffee;
    }

    /**
     * 获取价格,装饰器父类中直接转发"请求"至引用对象
     * @return
     */
    @Override
    public float getPrice() {
        return coffee.getPrice();
    }

    /**
     * 获取咖啡,装饰器父类中直接转发"请求"至引用对象
     * @return
     */
    @Override
    public String getCoffee() {
        return coffee.getCoffee();
    }
}
具体的装饰器类

具体的装饰器类,负责往咖啡中“添加”牛奶,注意看getPrice()方法和getCoffee()方法,可以在转发请求之前或者之后,增加功能。如果是代理模式,这里的结构就有所不同,通常代理模式根据运行时的条件来判断是否转发请求。

/**
 * 混合牛奶到蜂蜜中
 */
public class CreamCoffee extends DecoratorAbstractCoffee {
    private float price = (float) 0.5;

    /**
     * 调用父类的构造方法
     * @param coffee
     */
    public CreamCoffee(Coffee coffee) {
        super(coffee);
    }

    /**
     * 增加配料需要加钱
     * @return
     */
    @Override
    public float getPrice() {
        return coffee.getPrice()+price;
    }

    /**
     * 对咖啡进行加工
     * @return
     */
    @Override
    public String getCoffee() {
        return coffee.getCoffee()+";添加牛奶";
    }
}
添加糖

另一个具体装饰器类,用来给咖啡加蜂蜜,一样的逻辑。

class HoneyCoffee extends DecoratorAbstractCoffee {
    private float price = (float) 1.4;

    public HoneyCoffee(Coffee coffee) {
        super(coffee);
    }

    @Override
    public float getPrice() {
        return coffee.getPrice()+price;
    }

    @Override
    public String getCoffee() {
        return coffee.getCoffee()+";添加蜂蜜";
    }
}
客户端使用
public class DecoratorMain {

    public static void main(String[] args) {
        //是不是很像 javaIO中的 stream流
        Coffee coffee = new CreamCoffee(new HoneyCoffee(new OriginalCoffee()));
        System.out.println(coffee.getCoffee());
        System.out.println(coffee.getPrice());

    }
}

七.装饰者模式在Spring Boot中的应用

装饰者模式在Spring Boot中有着广泛的应用,主要用于动态地扩展和改变对象的行为和状态。以下是装饰者模式在Spring Boot中的一些常见应用:

  1. 自定义异常处理:Spring Boot允许你通过装饰者模式来为你的控制器添加自定义的异常处理。你可以创建一个异常处理器,然后通过装饰者模式将其添加到Spring MVC的异常处理器链中。这样,当控制器抛出异常时,你的自定义处理器就会被调用。
  2. 安全性控制:Spring Security是Spring Boot中用于安全性控制的一个库。它使用了装饰者模式来动态地为请求添加安全性检查。你可以创建一个自定义的安全性过滤器,然后将其添加到Spring Security的过滤器链中,以实现自定义的安全性控制。
  3. 响应式编程:Spring WebFlux是Spring Boot中的响应式编程框架。它使用了装饰者模式来动态地为服务器端点添加响应式处理。你可以创建一个自定义的响应式处理器,然后将其添加到WebFlux的处理器链中,以实现自定义的响应式处理逻辑。
  4. 拦截器:Spring MVC允许你使用拦截器来在控制器处理请求之前或之后执行一些操作。拦截器实际上就是使用了装饰者模式。你可以创建一个自定义的拦截器,然后将其添加到Spring MVC的拦截器链中,以实现自定义的请求拦截和处理。

这些应用只是装饰者模式在Spring Boot中的一部分。事实上,只要你需要动态地扩展和改变对象的行为和状态,装饰者模式就可能是一个好的解决方案。

八.总结

​ 装饰器模式是代替增加子类的一种解决方案,体现了聚合/合成复用原则的思想,尽量使用组合的方式来扩展功能,这样就把基本功能和扩展功能解耦了,使得代码可复用,可维护,灵活。关键点在于装饰器模式可以动态地为对象增加扩展功能。

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

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

相关文章

多列等高实现

预期效果 多列等高,左右两列高度自适应且一样,分别设置不同背景色效果预览: 分别由6种方法实现 1、使用padding + margin + overflow 实现多列等高效果,具有良好的兼容性; 2、border实现多列等高,左边框宽度为200px,左列浮动,伪元素清除浮动; 3、父元素线性渐变背景色…

Mac热门软件推荐Paste mac 中文激活版 剪切板工具

Paste for Mac是一款运行在Mac OS平台上的剪切板小工具。它拥有华丽的界面效果,并且每一条记录可显示(预览)文本、图片等记录的完整内容。此外,Paste for Mac可以记录最近指定条数的剪切板信息,方便用户随时调用&#…

L15D1 设备分类、设备号申请和注销

一、Linux设备分类 (一)linux的文件种类: -:普通文件:文件IOd:目录文件p:管道文件s:本地socket文件:网络编程l:链接文件c:字符设备b&#xff1a…

18__call__函数的调用

目录 把对象当成函数一样调用 吼吼~补充一个小的知识点哦~就是括号里的参数! 具体的应用场景 原先一个实例化对象,并不会被调用,但是可以引入call class Person:pass pPerson() p() 这个时候引入__call__ 把对象当成函数一样调用 class…

PLC电梯控制系统

目录 PLC电梯控制系统 1电梯简介 1.1电梯的基本分类 1.1.1按用途分类 1.1.2 按驱动系统分类 1.2 电梯的型号 1.3电梯的主要参数及规格尺寸 1.4电梯控制技术 1.5常用交流调速电梯的特点 1.6电梯的工作原理 2 PLC可编程序控制器 2.1 PLC的起源与发展 2.2 PLC控制系统…

视频监控系统/安防视频平台EasyCVR广场视频细节优化

安防视频监控系统/视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同,支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。安防视频汇聚平台EasyCVR拓展性强,视频能力丰富,可实现视频监控直播、视频轮播、…

二叉搜索树--查询节点-力扣 700 题

例题细节讲过(二叉搜索树的基础操作-CSDN博客)&#xff0c;下面给出递归实现 public TreeNode searchBST(TreeNode node, int val) {if(node null) {return null;}if(val < node.val) {return searchBST(node.left, val);} else if(node.val < val) {return searchBST(…

Iptabels的相关描述理解防火墙的必读文章

Iptabels是与Linux内核集成的包过滤防火墙系统&#xff0c;几乎所有的linux发行版本都会包含Iptables的功能。如果 Linux 系统连接到因特网或 LAN、服务器或连接 LAN 和因特网的代理服务器&#xff0c; 则Iptables有利于在 Linux 系统上更好地控制 IP 信息包过滤和防火墙配置。…

MATLAB笔记:GUI中的回调函数之间的数据传输

文章目录 效果代码 效果 plot 是画图 hold是hold on show是显示 clear是清除坐标轴 代码 function varargout untitled(varargin) % UNTITLED MATLAB code for untitled.fig % UNTITLED, by itself, creates a new UNTITLED or raises the existing % singleton*.…

Nacos(替代Eureka)注册中心

Nacos初步学习 Nacos 是一个开源的服务注册和配置中心&#xff0c;它允许您注册、注销和发现服务实例&#xff0c;并提供了配置管理的功能。下面是Nacos的最基础用法&#xff1a; 1. 服务注册和发现&#xff1a; 首先&#xff0c;您需要将您的应用程序或服务注册到Nacos中。…

抖音商品详情数据接口,抖音商品详情API接口

抖音商品详情API接口获取数据&#xff0c;接口对接可获取到商品标题&#xff0c;商品价格&#xff0c;商品优惠价&#xff0c;优惠券信息&#xff0c;店铺昵称&#xff0c;sku信息&#xff0c;sku主图&#xff0c;视频链接&#xff0c;详情主图&#xff0c;库存&#xff0c;数量…

路由高级特性

项目拓扑与项目需求 项目需求 某企业网络使用ospf和isis作为IGP协议实现内部网络的互联互通&#xff0c;区域规划和IP规划如图所示&#xff0c;现在要求实现如下需求&#xff1a; LSW1和AR1使用vlan10互联&#xff0c;与AR2使用vlan20互联&#xff0c;LSW1与LSW2、3、4之间使…

MySQL实践——MySQL权限

1. 权限概述 MySQL的mysql 系统库提供了user、db、tables_priv、columns_priv、procs_priv、proxies_priv几个表&#xff0c;用于存放不同权限范围的用户账号相关数据&#xff0c;这些表共同组成了MySQL的访问权限控制系统。 MySQL访问权限控制系统的主要功能是对从给定主机连…

springcloud学习笔记(3)-服务管理组件Nacos

Nacos简介 在2中学习了服务治理中心eureka&#xff0c;而本节的nacos来自springcloud alibaba。 Nacos也是一个服务注册和管理的组件。 Nacos 支持几乎所有主流类型的“服务”的发现、配置和管理 官方文档 快速开始 | Spring Cloud Alibaba (aliyun.com) 概述 | Spring C…

如何设计一个网络爬虫?

网络爬虫也被称为机器人或蜘蛛&#xff0c;它被搜索引擎用于发现网络上的新内容或更新内容。内容可以是网页、图片、视频、PDF文件等。网络爬虫开始时会收集一些网页&#xff0c;然后跟随这些网页上的链接收集新的内容。图9-1展示了爬取过程的可视化示例。 爬虫的作用&#xff…

Windows11下清理Docker Desktop与wsl的C盘空间占用

一、清理Docker Desktop的磁盘占用 //【查看docker 占用的空间】 docker system dfTYPE 列出了docker 使用磁盘的 4 种类型&#xff1a; Images&#xff1a;所有镜像占用的空间&#xff0c;包括拉取下来的镜像&#xff0c;和本地构建的。Containers&#xff1a;运行的容器占用…

scratch保护环境 2023年5月中国电子学会图形化编程 少儿编程 scratch编程等级考试一级真题和答案解析

目录 scratch保护环境 一、题目要求 1、准备工作 2、功能实现 二、案例分析

基于YOLO算法的单目相机2D测量(工件尺寸和物体尺寸)

1.简介 1.1 2D测量技术 基于单目相机的2D测量技术在许多领域中具有重要的背景和意义。 工业制造&#xff1a;在工业制造过程中&#xff0c;精确测量是确保产品质量和一致性的关键。基于单目相机的2D测量技术可以用于检测和测量零件尺寸、位置、形状等参数&#xff0c;进而实…

【C++项目】手动实现一个定长内存池(了解内存分配机制、定长内存提高效率 附源码)

定长内存池 1.项目介绍2.代码部分3.测试结果4.相关细节分析总结 1.项目介绍 这是一个 C 中的对象池&#xff08;Object Pool&#xff09;的简单实现&#xff0c;用于更有效地管理对象的内存分配和回收。对象池是一种内存管理技术&#xff0c;旨在减少频繁分配和释放对象的开销&…

大日志(大文件)查看工具

一款很不错的日志查看工具&#xff0c; 优势是能查看很大的日志文档。 无需安装&#xff0c;解压后运行即可&#xff1b; 有注册版&#xff0c;不注册也可以使用。 官方地址&#xff1a; LogViewer - Home page 一个下载地址&#xff1a; 日志查看工具UVviewsoft LogViewer(超大…