【结构型模式】装饰器模式

​一、装饰器模式概述

        装饰器模式(装饰者模式)定义装饰器模式动态地将责任附加到对象上。若要拓展功能,装饰者提供了比继承更有弹性地替代方案。(对象结构型模型)通俗点来说:动态的给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。

  • 利用继承来达到“类型匹配”
    • 1.装饰者与被装饰对象有相同地超类型;
    • 2.可以用一个或多个装饰者包装一个对象;
    • 3.既然装饰者与被装饰对象有相同地超类型,所以在任何需要原始对象(被包装地)的场合,可以用装饰过的兑现代替它;
    • 4.装饰者可以在所委托被装饰者的行为之前与/之后,加上自己的行为,以达到特定的目的;
    • 5.对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
  •  装饰模式分析
    • 1.可以在不改变一个对象本身功能的基础上给对象增加额外的新行为;
    • 2.是一种用于替代继承的技术,它通过一种无需有定义子类的方式给对象动态增加职责,使用对象之间的关联关系取代类之间的继承关系;
    • 3.引入了装饰类,在装饰类中既可以调用装饰的原有类的方法,还可以增加新的方法,以扩展原有类的功能。

        ​透明装饰模式与半透明装饰模式

  • 半透明装饰模式
    • 1.可以给系统带来更多的灵活性,设计相对简单,使用起来也方便;
    • 2.客户端使用具体装饰类型来定义装饰后的对象,因此可以单独调用addedBehavior()方法;
    • 3.最大的缺点在于不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象;
    • 4.用具体装饰定义装饰之后的对象,而具体构件使用抽象构件类型来定义;
    • 5.对于客户而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这并不是透明的。
  • 透明装饰模式
    • 1.要求客户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型;
    • 2.对客户端而言,具体构件对象和具体装饰对象没有任何区别;
    • 3.可以让客户透明地使用装饰之前地对象和装饰之后地对象,无须关心他们的区别;
    • 4.可以对一个已装饰过地对象进行多次装饰,得到更多复杂、功能更为强大的对象;
    • 5.无法在客户端单独调用新增addedBehavior()方法
  • 适用环境
    • 1.在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责;
    • 2.当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式

        装饰者模式优缺点

  • 优点
    • 1.对于扩展一个对象功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加;
    • 2.可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为;
    • 3.可以对一个对象进行多次装饰;
    • 4.具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无需变化,符合开闭原则。
  • 缺点
    • 1.使用装饰模式进行系统设计时将产生很多小对象,大量对象对象的产生势必会占用更多的系统资源,在一定程度上影响程序的性能;
    • 2.比继承更加易于出错,排错也更困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。

二、代码实现

        结构包含四个角色:

  • 抽象构件(Component)
  • 具体构件(ConcreteComponent)
  • 抽象装饰类(Decorator)
  • 具体装饰类(ConcreteDecorator)
         2.1 星巴兹咖啡

        2.1.1 抽象构件(抽象基类饮料Beverage)
package decorator.dec;
//抽象构件:饮料
public abstract class Beverage {
	String description = "Unknown Noodle";
	int size;
	//小杯TALL、中杯GRANDE、大杯WENTI
	public final static int TALL=1;
	public final static int GRANDE=2;
	public final static int WENTI=3;
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public int getSize() {
		return size;
	}
	public void setSize(int size) {
		this.size = size;
	}
	public abstract double cost();
}
        2.1.2 具体构件(基于饮料的咖啡:DarkRoast、Decaf、Espressio、HouseBlend)
package decorator.dec;
//意大利浓咖啡
public class DarkRoast extends Beverage{
	public DarkRoast() {
		description = "DarkRoast";
	}
	public double cost() {
		return 3;
	}
}
package decorator.dec;
//不加咖啡因的咖啡
public class Decaf extends Beverage{
	public Decaf() {
		description = "Decaf";
	}
	public double cost() {
		return 2;
	}
}
package decorator.dec;
//意式浓缩咖啡
public class Espressio extends Beverage{
	public Espressio() {
		description = "Espressio";
	}
	public double cost() {
		return 2.5;
	}
}
package decorator.dec;
//混合咖啡
public class HouseBlend extends Beverage{
	public HouseBlend() {
		description = "HouseBlend";
	}
	public double cost() {
		return 1.5;
	}
}
        2.1.3 抽象装饰类(抽象装饰类CondimentDecorator)
package decorator.dec;
//抽象装饰类:描述->>配料继承父类,附加在父类上
public abstract class CondimentDecorator extends Beverage{
	Beverage beverage;
	public abstract String getDescription();
}
        2.1.4 具体装饰类(添加在咖啡上的牛奶milk、抹茶Mocha、豆奶Soy、咖啡的大小Size、搅拌Whip)
package decorator.dec;
//牛奶
public class milk extends CondimentDecorator{
	public milk(Beverage beverage) {
		this.beverage=beverage;
	}
	public String getDescription() {
		return beverage.getDescription() + ",Milk";
	}
	public double cost() {
		return 1+beverage.cost();
	}
}
package decorator.dec;
//抹茶
public class Mocha extends CondimentDecorator {
	public Mocha(Beverage beverage) {
		this.beverage=beverage;
	}
	@Override
	public String getDescription() {
		// TODO 自动生成的方法存根
		return beverage.getDescription() + ",Mocha";
	}
	public double cost() {
		return 1+beverage.cost();
	}

}
package decorator.dec;
//豆奶
public class Soy extends CondimentDecorator {
	public Soy(Beverage beverage) {
		this.beverage=beverage;
	}
	@Override
	public String getDescription() {
		return beverage.getDescription() + ",Soy";
	}
	public double cost() {
		return 1+beverage.cost();
	}
}
package decorator.dec;
//大小
public class Size extends CondimentDecorator {

	public Size(Beverage beverage,int size) {
		this.beverage = beverage;
		this.size=size;
	}
	@Override
	public String getDescription() {
		// TODO 自动生成的方法存根
		if(size == beverage.TALL) {
			return beverage.getDescription() + ",小杯";
		}else if(size == beverage.GRANDE) {
			return beverage.getDescription() + ",中杯";
		}else if(size == beverage.WENTI) {
			return beverage.getDescription() + ",大杯";
		}
		return null;
	}

	@Override
	public double cost() {
		double cost = beverage.cost();
		if(size == beverage.TALL) {
			cost += 0.1;
		}else if(size == beverage.GRANDE) {
			cost +=0.2;
		}else if(size == beverage.WENTI) {
			cost +=0.3;
		}
		return cost;
	}

}
package decorator.dec;
//搅拌
public class Whip extends CondimentDecorator {
	//Noodle beverage;
		public Whip(Beverage beverage) {
			this.beverage=beverage;
		}
		@Override
		public String getDescription() {
			return beverage.getDescription() + ",Whip";
		}
		public double cost() {
			return 1+beverage.cost();
		}
}
        2.1.5  main方法实现装饰者模式
package decorator.dec;

public class Test {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		Beverage beverage1 =new Mocha(new milk(new DarkRoast()));
		System.out.println(beverage1.getDescription()+" 合计$"+beverage1.cost());
		Beverage beverage2 =new Mocha(new milk(new DarkRoast()));
		Beverage beverage3 =new Size(new Mocha(new milk(new DarkRoast())),2);
		Beverage size = new Size(beverage2,2);
		System.out.println(size.getDescription()+" 合计$"+size.cost());
	}
}
        2.1.6 UML图

        2.2 窗口显示
        2.2.1 抽象构件(抽象基类:显示构件Component)
package decorator.visualCompanent;
//显示构件
public abstract class Component {
	public abstract void display();
}
        2.2.2 具体构件(列表框、文本框、窗体)
package decorator.visualCompanent;

public class ListBox extends Component {

	@Override
	public void display() {
		// TODO 自动生成的方法存根
		System.out.println("显示列表框!");
	}

}
package decorator.visualCompanent;

public class TextBox extends Component {

	@Override
	public void display() {
		// TODO 自动生成的方法存根
		System.out.println("显示文本框!");
	}

}
package decorator.visualCompanent;

public class Window extends Component {

	@Override
	public void display() {
		// TODO 自动生成的方法存根
		System.out.println("显示窗体!");
	}

}
         2.2.3 抽象装饰类(ComponentDecorator)
package decorator.visualCompanent;

public class ComponentDecorator extends Component{
	private Component component;//维持对抽象构件类型对象的引用
	
	//注入抽象构件类型的对象
	public ComponentDecorator(Component component) {
		this.component = component;
	}
	public void display() {
		component.display();
	}
}
          2.2.4 具体装饰类(增加新的构件:黑色边框和滚动条)
package decorator.visualCompanent;

public class BlackBorderDecorator extends ComponentDecorator {
	public BlackBorderDecorator(Component component) {
		super(component);
	}
	public void display() {
		// TODO 自动生成的方法存根
		this.setBlackBorder();
		super.display();
	}
	public void setBlackBorder() {
		System.out.println("为构件增加黑色边框!");
	}
}
package decorator.visualCompanent;

public class ScrollBarDecorator extends ComponentDecorator {
	public ScrollBarDecorator(Component component) {
		super(component);
	}
	public void display() {
		// TODO 自动生成的方法存根
		this.setScrollBar();
		super.display();
	}
	public void setScrollBar() {
		System.out.println("为构件增加滚动条!");
	}

}
        2.2.5 main方法实现装饰者模式
package decorator.visualCompanent;

public class Client {

	public static void main(String[] args) {
		// TODO 自动生成的方法存根
		//使用抽象构件定义全部对象
		Component component,componentSB,componentBB;
		component = new Window(); //创建具体对象
		//创建装饰后的构件对象
		componentSB = new ScrollBarDecorator(component);
		//将装饰了一次的对象
		componentBB = new BlackBorderDecorator(componentSB);
		componentBB.display();
	}

}
        2.2.6 UML图

三、代码结构图

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

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

相关文章

适用于 Windows 的 10 个顶级 PDF 编辑器 [免费和付费]

曾经打开PDF文件,感觉自己被困在数字迷宫中吗?无法编辑的文本、无法调整大小的图像以及签署感觉像是一件苦差事的文档?好吧,不用再担心了!本指南解开了在 Windows 上掌握 PDF 的秘密,其中包含 10 款适用于 …

vscode vue template模板中 tab键无法快速补全

之前记得一直可以的突然不知道咋的就不行了… 解决办法: 菜单栏 - 文件 - 首选项 - 设置- emmet:tab ✔就好了

Flink CDC 的 debezium-json 格式和 debezium 原生格式是一回事吗?

博主历时三年精心创作的《大数据平台架构与原型实现:数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行,点击《重磅推荐:建大数据平台太难了!给我发个工程原型吧!》了解图书详情,…

【介绍下负载均衡原理及算法】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出…

IP协议如何进行地址管理?

如今,IP协议有两个版本,分别是IPv4和IPv6,IPv4是目前主要应用的版本。IPv4的IP地址是以4个字节的数字来表示的,比如 127.0.0.1。因此,IPv4所能表示IP地址的个数是2^32次方,也就是42亿多个,看起来…

48.HarmonyOS鸿蒙系统 App(ArkUI)常用组件的使用

48.HarmonyOS鸿蒙系统 App(ArkUI)常用组件的使用 按钮触发事件 toast信息提示 单选按钮 复选框 切换按钮,开关按钮 进度条 textbox,textinput,TextArea文本输入框 气泡提示 import prompt from ohos.prompt; import promptAction from ohos.promptAction; …

Qt对象池,单例模式,对象池可以存储其他类的对象指针

代码描述: 写了一个类,命名为对象池(ObjectPool ),里面放个map容器。 3个功能:添加对象,删除对象,查找对象 该类只构建一次,故采用单例模式功能描述:对象池可…

【ARFoundation自学01】搭建AR框架,检测平面点击位置克隆物体

Unity开发ARFoundation相关应用首先安装ARFoundation包 然后设置XR 1.基础AR场景框架搭建 2.一个基本的点击克隆物体到识别的平面脚本 挂在XROrigin上 脚本AppController 脚本说明书 ## 业务逻辑 AppController 脚本旨在实现一个基本的 AR 应用程序功能:用户通过…

Spring Cloud+Uniapp 智慧工地云平台源码 智慧工地云平台AI视频分析应用

目录 AI应用与环境治理 设备管理与危大工程 塔吊安全监管 智慧工地APP端 智慧工地硬件设备 智慧工地主要功能模块 智慧工地可以通过以下几个方面为建筑行业赋能: 1.提高工程效率 2.提高工程安全性 3.提高工程质量 4.提高工程管理效率 绿色施工 质量管理…

Codeforces Round 924 (Div. 2) --- E. Modular Sequence ---- 题解

E. Modular Sequence: 题目描述: 思路解析: 这里第一个一定要需要填充x,然后后面每一位填充 ai-1 y 或者 ai-1 % y,那么其实相当于除了第一位固定,后面每一位都可以表现为 a ki * y;其中 a …

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之十二 简单人脸识别

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之十二 简单人脸识别 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单人脸检测/识别实战案例 之十二 简单人脸识别 一、简单介绍 二、简单人脸识别实现原理 三、简单人脸识别案例实现简…

RAID 磁盘阵列及RAID配置实战

目录 一.RAID磁盘阵列介绍 二.常用的RAID磁盘阵列的介绍 1.RAID 0 (条带化存储) 2.RAID 1(镜像存储) 3.RAID 5 4.RAID 6 5.RAID 10(先做镜像,再做条带) 6.RAID 01 (先做条带…

Java代码执行顺序

Java代码的执行顺序 后面大量的涉及到了static,我曾经写过一篇static的博客,可以看一眼 我上次写了static的加载顺序,没看过的可以进去看一眼 JavaSE:static关键字详解 ---------------------分割线-------------------------…

魔方网表 存在 mailupdate.jsp接口 任意文件上传漏洞

声明: 本文仅用于技术交流,请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。 简介 魔方网表mailupdate.jsp接口存在任意文件上传漏洞 …

Jenkins配置windows/linux从节点

背景: 环境:jenkins环境(Ubuntu) 节点机器:Linux、Windows 前置条件: 节点机器:安装java、allure、python 1 Linux节点管理机器添加 1.1 系统管理->节点列表->New Node 1.2 节点配置…

Python --- 在python中安装NumPy,SciPy和Matplotlib(Windows平台)

在python中安装NumPy,SciPy和Matplotlib(Windows平台) NumPy NumPy是Python的一个最常用最基本的扩展程序库之一,主要用于矩阵运算或数组计算。很多其他的python库都要依赖于NumPy才能跑。 NumPy的发展史: Matrix-sig 1995年,特殊…

RabbitMQ - Spring boot 整合 RabbitMQ

一、RabbitMQ 1、RabbitMQ 使用场景 1.1、服务解耦 假设有这样一个场景, 服务A产生数据, 而服务B,C,D需要这些数据, 那么我们可以在A服务中直接调用B,C,D服务,把数据传递到下游服务即可 但是,随着我们的应用规模不断扩大,会有更多的服务需要A的数据,如果有几十甚至几百个下…

系统调优助手,PyTorch Profiler TensorBoard 插件教程

0x1. 前言 使用PyTorch Profiler进行性能分析已经一段时间了,毕竟是PyTorch提供的原生profile工具,个人感觉做系统性能分析时感觉比Nsys更方便一些,并且画的图也比较直观。这里翻译一下PyTorch Profiler TensorBoard Plugin的教程并分享一些…

SEO之搜索引擎的工作原理(三)

初创企业需要建站的朋友看这篇文章,谢谢支持:我给不会敲代码又想搭建网站的人建议 (接上一篇。。。) 排名 经过搜索引擎蜘蛛抓取页面,索引程序计算得到倒排索引后,搜索引擎就准备好可以随时处理用户搜索了…

基于Echarts的超市销售可视化分析系统(数据+程序+论文

本论文旨在研究Python技术和ECharts可视化技术在超市销售数据分析系统中的应用。本系统通过对超市销售数据进行分析和可视化展示,帮助决策层更好地了解销售情况和趋势,进而做出更有针对性的决策。本系统主要包括数据处理、数据可视化和系统测试三个模块。…