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

news2024/9/19 11:11:53

​一、装饰器模式概述

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

  • 利用继承来达到“类型匹配”
    • 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.coloradmin.cn/o/1612318.html

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

相关文章

12.事件参数

事件参数 事件参数可以获取event对象和通过事件传递数据 获取event对象 <template><button click"addCount">Add</button><p>Count is: {{ count }}</p> </template> <script> export default {data() {return {count:0…

13.Hexo Plugins插件及将网站上传到互联网

Plugins 有些想要实现的操作Hexo实现不了&#xff0c;这时就可以使用插件 插件一般都是可以下载的代码片段&#xff0c;可以附加到Hexo上 添加了一些功能或一些额外的东西 Plugins | Hexo 在官方页面&#xff0c;有471个插件&#xff0c;并附加了一些描述 点击一个插件时&…

【研发管理】产品经理知识体系-文化、团队与领导力

导读&#xff1a;文化、团队与领导力是产品经理知识体系中的重要组成部分。产品经理需要深入理解并应用这些要素&#xff0c;以推动产品的成功开发和运营。通过塑造积极的文化氛围、建立高效的团队和发挥领导力&#xff0c;产品经理能够为公司创造更大的价值。 目录 概述 1、…

(1)认识人工智能

第一章 认识人工智能 引言 本人目前大三&#xff0c;双非一本的人工智能专业&#xff0c;代码能力不算太差&#xff0c;做过项目&#xff0c;也打了比赛&#xff0c;获了奖&#xff0c;但是走技术路线总会有否定自己的感觉&#xff0c;可能是感觉自己的才能没有在搞技术方面实…

#QT获取ONENET云平台数据(草稿)

1.基本目标 &#xff08;1&#xff09;查询ONENT云平台的数据 &#xff08;2&#xff09;查询网络时间 &#xff08;3&#xff09;网络音乐拉取&#xff08;作为背景音乐&#xff09;&#xff0c;音量可调 2.制作UI界面 &#xff08;1&#xff09;串口图标的制作方法 &…

RIME-SVM,基于RIME寒冰优化算法优化SVM支持向量机回归预测 (多输入单输出)-附代码

支持向量机&#xff08;SVM&#xff09; 支持向量机&#xff08;SVM&#xff09;是一种广泛用于分类和回归的强大监督学习算法。在回归任务中&#xff0c;特别是在SVM被用作支持向量回归&#xff08;SVR&#xff09;时&#xff0c;目标是找到一个函数&#xff0c;这个函数在给…

PMP证书难考吗?

PMP证书难不难考要看你学的咋样的&#xff0c;我的PMP认证就是一个多月拿下的&#xff0c;同一个考次的同学在考试前的讲师直播过程中一直在说冲刺题难怎么怎么滴&#xff0c;最后还是通过率98%&#xff0c;绝大多数都通过了&#xff0c;并且还有47%的同学考了3A&#xff0c;这…

Vue2slot插槽(理解与应用)

1、插槽的概念 插槽&#xff08;Slot)是vue为组件的封装者提供的能力。允许开发者在封装组件时&#xff0c;把不确定的、希望由用户指定的部分定义为插槽。 举个例子&#xff1a;组件好比小霸王游戏机&#xff0c;插槽就是游戏机的插口&#xff0c;看用户插什么卡&#xff0c;就…

笔记 | 嵌入式系统概论

1 嵌入式系统简介 1.1 嵌入式系统的定义 根据美国电气与电子工程师学会&#xff08;IEEE&#xff1a;Institute of Electrical and Electronics Engineers )的定义&#xff0c;嵌入式系统是用于控制、监视或辅助操作机器和设备的装置(原文: devices used to control, monitor…

【Java基础】23.接口

文章目录 一、接口的概念1.接口介绍2.接口与类相似点3.接口与类的区别4.接口特性5.抽象类和接口的区别 二、接口的声明三、接口的实现四、接口的继承五、接口的多继承六、标记接口 一、接口的概念 1.接口介绍 接口&#xff08;英文&#xff1a;Interface&#xff09;&#xf…

Virtualenv:Python项目管理的救星

在Python的世界里&#xff0c;依赖包冲突是开发者的噩梦&#xff0c;但也是成长的催化剂。最近在写Python项目中就碰到了这样的问题&#xff0c;明明代码在自己的电脑上表现都是正常的&#xff0c;在另外一台电脑上却始终有些小问题&#xff0c;两台电脑安装的Python版本都是一…

云原生Docker容器中的OpenCV:轻松构建可移植的计算机视觉环境

前言 构建可移植的计算机视觉环境 文章目录 前言引言简介&#xff1a;目的和重要性&#xff1a; 深入理解Docker和OpenCVDocker的基本概念和优势&#xff1a;OpenCV简介和应用领域&#xff1a; 构建Docker镜像部署分享Docker容器1. 打包Docker镜像:2. 上传到Docker镜像仓库:3. …

【python】Paste Mask

学习来自【OpenCv】利用roi 掩模 将一张图片添加到另一张上 任务描述&#xff1a;提取图片A的 mask 区域&#xff0c;并粘贴到图片B上 文章目录 1 代码实现2 结果展示3 涉及到的库cv2.bitwise_notcv2.bitwise_andcv2.add 附录——获取 mask 的边界框 1 代码实现 A 图 A 图的 …

Pytest精通指南(23)钩子函数-执行顺序(pytest-ordering)

文章目录 前言应用场景插件安装参数分析装饰方法装饰类装饰模块 前言 pytest-ordering 是一个pytest插件&#xff0c;它允许用户自定义测试用例的执行顺序。 默认情况下&#xff0c;pytest会按照模块、类、函数定义的顺序以及它们的名称的字母顺序来执行测试用例。 但通过使用 …

Kafka集群搭建可视化指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 Kafka集群搭建可视化指南 前言准备工作硬件要求环境准备 kafka集群的部署与配置3.1 单节点部署与多节点集群搭建单节点部署&#xff1a;多节点集群搭建&#xff1a; 3.2 Broker配置与优化3.3 Topic的创…

竞赛 基于LSTM的天气预测 - 时间序列预测

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 机器学习大数据分析项目 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/po…

C++:面向对象大坑:菱形继承

菱形继承 1.单继承1.概念 2.多继承2.1概念2.2菱形继承1.概念2.问题3.样例理解二义性数据冗余对于内存模型抽象化 2.3菱形虚拟继承&#xff08;解决菱形继承的问题&#xff09;1.概念2.样例理解对于内存模型抽象化 2.4总结 3.问题总结1.C有多继承&#xff0c;为什么&#xff1f;…

react中useState的值没有改变,而是旧的数值

问题背景 想实现点击按钮就改变数据的效果&#xff0c;但是在控制台的打印结果&#xff0c;总是上一次的修改情况&#xff0c;并不是最新的修改后的数据 代码&#xff1a; import { useState, useRef } from "react";// 实现sonA的数据传递给sonB const SonA () …

史上最全的四分之一、半车再到全车7自由度常规悬架建模与仿真之一

一、悬架建模的简化过程 汽车是一个复杂的振动系统&#xff0c;针对不同的需求进行不同的简化。在对悬架振动分析中&#xff0c;把汽车车身看做一个刚体&#xff0c;把驾驶员座椅和驾驶员拿掉&#xff1b;车身以下至车轮之间的橡胶垫&#xff0c;连接杆&#xff0c;弹簧等具有…

智慧化转型赋能园区创新:科技创新引领产业智慧化,打造高效发展新格局

在全球化和信息化浪潮的推动下&#xff0c;园区作为区域经济发展的重要引擎&#xff0c;正面临着前所未有的机遇与挑战。为应对这些挑战并把握机遇&#xff0c;园区需积极拥抱智慧化转型&#xff0c;通过科技创新引领产业智慧化&#xff0c;打造高效发展的新格局。本文将深入探…