设计模式之装饰模式解析

装饰模式
1)概述
1.定义

动态地给一个对象增加一些额外的职责,在增加对象功能时,装饰模式比生成子类实现更为灵活。

2.作用

装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。

3.结构图

在这里插入图片描述

4.角色
  • Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

  • ConcreteComponent(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

  • Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现,它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。

  • ConcreteDecorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责,每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

5.代码案例

抽象装饰类

public class Decorator implements Component {//维持一个对抽象构件对象的引用private Component component;//注入一个抽象构件类型的对象public Decorator(Component component){this.component = component;}public void operation() {//调用原有业务方法component.operation();}
}

注意:在Decorator中并未实现operation()方法,而只是调用原有component对象的operation()方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。

具体装饰类

public class ConcreteDecorator extends Decorator {public ConcreteDecorator(Component component) {super(component);}public void operation() {super.operation();  //调用原有业务方法addedBehavior();  //调用新增业务方法}//新增业务方法public void addedBehavior() {……}
}

注意:由于在抽象装饰类Decorator中注入的是Component类型的对象,因此可以将一个具体构件对象注入其中,再通过具体装饰类来进行装饰;此外,还可以将一个已经装饰过的Decorator子类的对象再注入其中进行多次装饰,从而对原有功能进行多次扩展。

2)案例-完整解决方案
1.结构图

在这里插入图片描述

Component充当抽象构件类,其子类Window、TextBox、ListBox充当具体构件类,Component类的另一个子类ComponentDecorator充当抽象装饰类,ComponentDecorator的子类ScrollBarDecorator和BlackBorderDecorator充当具体装饰类。

2.代码案例

抽象构件类

//抽象构件类
abstract class Component {public abstract void display();
}

具体构件类

//具体构件类
public class Window extends Component {public void display() {System.out.println("显示窗体!");}
}//具体构件类
public class TextBox extends Component {public void display() {System.out.println("显示文本框!");}
}

抽象装饰类

//抽象装饰类
public class ComponentDecorator extends Component {//维持对抽象构件类型对象的引用private Component component;//注入抽象构件类型的对象public ComponentDecorator(Component component){this.component = component;}public void display() {component.display();}
}

具体装饰类

//黑色边框装饰类:具体装饰类
public class BlackBorderDecorator extends ComponentDecorator {public BlackBorderDecorator(Component component) {super(component);}public void display() {this.setBlackBorder();super.display();}public void setBlackBorder() {System.out.println("为构件增加黑色边框!");}
}

客户端类

public class Client{public  static void main(String[] args) {//使用抽象构件定义Component component,componentBB;//定义具体构件component = new Window();//定义装饰后的构件componentBB = new BlackBorderDecorator(component);componentBB.display();}
}
3)透明装饰模式与半透明装饰模式
1.透明装饰模式

a) 定义

在透明装饰模式中,要求客户端完全针对抽象编程。

客户端程序不应该将对象声明为具体构件类型或具体装饰类型,而应该全部声明为抽象构件类型。

b) 代码案例

//使用抽象构件类型定义对象
Component  c, c1; c = new ConcreteComponent();
c1 = new ConcreteDecorator (c);

c) 注意

透明装饰模式可以让客户端透明地使用装饰之前的对象和装饰之后的对象,无须关心它们的区别。

可以对一个已装饰过的对象进行多次装饰,得到更为复杂、功能更为强大的对象。

在实现透明装饰模式时,要求具体装饰类的operation()方法覆盖抽象装饰类的operation()方法,除了调用原有对象的operation()外还需要调用新增的addedBehavior()方法来增加新行为。

2.半透明装饰模式

a) 定义

用具体装饰类型来定义装饰之后的对象,而具体构件类型还可以使用抽象构件类型来定义。

对客户端而言,具体构件类型无须关心,是透明的;但是具体装饰类型必须指定,这是不透明的。

b) 代码案例

……
//使用抽象构件类型定义
Document  doc; 
doc = new PurchaseRequest();//使用具体装饰类型定义
Approver newDoc; 
newDoc = new Approver(doc);
……

c) 注意

半透明装饰模式可以给系统带来更多的灵活性,设计相对简单,使用起来也非常方便。

不能实现对同一个对象的多次装饰,而且客户端需要有区别地对待装饰之前的对象和装饰之后的对象。

4)总结
1.优点
  • 对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加。

  • 可以通过动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。

  • 可以对一个对象进行多次装饰,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出不同行为的组合,得到功能更为强大的对象。

  • 具体构件类与具体装饰类可以独立变化,可以根据需要增加新的具体构件类和具体装饰类,原有类库代码无须改变,符合“开闭原则”。

2.缺点
  • 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,大量小对象的产生势必会占用更多的系统资源,在一定程序上影响程序的性能。

  • 装饰模式提供了一种比继承更加灵活机动的解决方案,但也意味着比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。

3.适用场景
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

  • 当不能采用继承的方式对系统进行扩展或者采用继承不利于系统扩展和维护时可以使用装饰模式。

不能采用继承的情况

第一类是系统中存在大量独立的扩展,为支持每一种扩展或者扩展之间的组合将产生大量的子类,使得子类数目呈爆炸性增长;

第二类是因为类已定义为不能被继承(如Java语言中的final类)。

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

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

相关文章

【React】React 内置 Hook

React 内置 Hook 是一组允许你在函数组件中使用 state 和其他 React 特性的函数。它们极大地扩展了函数组件的功能,使得在无需编写 class 的情况下也能使用 React 的全部功能。以下是一些主要的 React 内置 Hook 的介绍: 1.useState useState 是用于在函数组件中添加状态(…

深入理解 @Transactional 注解在 Spring 中的应用

前言:在 Java 开发中,事务管理是非常重要的一环。Spring 框架提供了Transactional注解来简化事务管理的操作,本文将深入介绍Transactional注解的用法,并结合代码示例进行详细讨论。 1.Transactional 注解简介 Transactional注解是…

银行卡的分类

银行卡是银行账户的一种体现形式,它是由银行机构发行的具有消费信用、转账结算、存取现金等全部或部分功能作为结算支付工具的各类卡的统称。 (1)按是否具有授信额度分类 ①借记卡:借记卡是指发卡银行向申请人签发的,没…

Machine Learning机器学习之向量机(Support Vector Machine,SVM)

目录 前言 算法提出背景: 核心思想: 原理: 应用领域: 一、支持向量机分类(主要变体) 二、构建常见的支持向量机模型 基于Python 中的 Scikit-learn 库构建线性支持向量机(SVM) 三、向…

06. 详解 Java 的 Object 类和常见类

Object 类 java.lang.Object 作为所有 Java 类的祖先&#xff0c;编译系统默认继承 Object 类&#xff0c;Object 类包含了所有 Java 类的公共属性和方法。 Object() 构造方法getClass():Class<?>public boolean equals(Object obj) 比较两对象封装的数据是否相等&…

SQLite中的动态内存分配(五)

返回&#xff1a;SQLite—系列文章目录 上一篇&#xff1a;SQLite中的原子提交&#xff08;四&#xff09; 下一篇&#xff1a;SQLite使用的临时文件&#xff08;二&#xff09; ​概述 SQLite使用动态内存分配来获得 用于存储各种对象的内存 &#xff08;例如&#xff1a…

Django开发复盘

一、URL 对于一个不会写正则表达式的蒟蒻来说&#xff0c;在urls.py中就只能傻傻的写死名字&#xff0c;但是即便这样&#xff0c;还会有很多相对路径和绝对路径的问题&#xff08;相对ip端口的路径&#xff09;&#xff0c;因为我们网页中涉及到页面跳转&#xff0c;涉及到发送…

uniapp 用web-view 嵌套uniapp

1. uniapp 用web-view 嵌套uniapp uniapp开发的APP要嵌套uniapp开发的h5,并且APP后面还要打包H5,这就涉及app和h5之间的通信,h5和h5之间的通信。 1.1. 准备工作 无论是app和h5通信还是 h5和h5之间的通信都是需要引入web-view的sdk文件 我下载的是1.5.2版本,代码如下 !(functi…

目标检测系列模型发展历程

常见数据集&#xff1a; VOC-->COCO 模型发展&#xff1a; RCNN-->Fast RCNN-->Faster RCNN-->Mask RCNN 这一系列的模型&#xff08;RCNN、Fast RCNN、Faster RCNN、Mask RCNN&#xff09;代表了计算机视觉特别是在物体检测和分割领域的一系列重大进展。下面&a…

神经网络:梯度下降法更新模型参数

作者&#xff1a;CSDN _养乐多_ 在神经网络领域&#xff0c;梯度下降是一种核心的优化算法&#xff0c;本文将介绍神经网络中梯度下降法更新参数的公式&#xff0c;并通过实例演示其在模型训练中的应用。通过本博客&#xff0c;读者将能够更好地理解深度学习中的优化算法和损…

【LeetCode】20. 有效的括号(Java自用版)

栈 首先&#xff0c;我们定义一个isValid方法&#xff0c;该方法接受一个字符串s作为参数&#xff0c;并返回一个布尔值来表示该字符串是否有效。 public boolean isValid(String s) {// 如果字符串为空&#xff0c;则自然是有效的if (s.isEmpty())return true;// 创建一个栈…

帆软报表在arm架构的linux

有朋友遇到一个问题在部署帆软报表时遇到报错。 问 我在 arm架构的linux服务器上部署帆软报表遇到了一个棘手的问题&#xff0c;你有空帮忙看下嘛。 我看后台日志报的错是 需要升级 gcc、libmawt.so &#xff0c;是系统中缺少Tomcat需要的依赖库&#xff0c;你之前处理过类似…

超级会员卡积分收银系统源码:积分+收银+商城三合一小程序 带完整的安装代码包以及搭建教程

信息技术的迅猛发展&#xff0c;移动支付和线上购物已经成为现代人生活的常态。在这样的背景下&#xff0c;商家对于能够整合收银、积分管理和在线商城的综合性系统的需求日益强烈。下面&#xff0c;罗峰给大家分享一款超级会员卡积分收银系统源码&#xff0c;它集积分、收银、…

机器学习(复试)

学习分类 其学习形式主要分为&#xff1a;有监督学习、无监督学习、半监督学习 有监督 有监督学习&#xff08;supervised learning&#xff09;&#xff0c;需要你事先需要准备好要输入数据&#xff08;训练样本&#xff09;与真实的输出结果&#xff08;参考答案) 预测结…

vector类(一)

文章目录 vector介绍和使用1.vector的介绍2.vector的使用2.1 vector的定义2.2 vector iterator的使用2.3 vector空间增长问题2.4 vector增删查改2.5 vector迭代器失效问题 3.vector 在OJ中的使用 vector介绍和使用 1.vector的介绍 vector是表示 可变大小数组的 序列容器。 就…

四、harmonyos实操一个toDoItem待办列表

官方讲的很大概&#xff0c;有些细节得去看源码才能知道&#xff0c;不过还是撸出来一个简易版的的item了 import image from ohos.multimedia.image;Entry // 表示入口 Component struct Index {State isComplete:boolean false;private totalTasks: Array<string> […

《数据结构学习笔记---第五篇》---链表OJ练习上

目录 CM11链表分割 OR36 链表的回文结构 160.相交链表 141&142环形链表 CM11链表分割 step1:思路分析 1.首先可以想到&#xff0c;我们可以将原链表的元素划分到两个新的链表之中&#xff0c;由于必须保持顺序&#xff0c;所以新链表我们要用尾插。 2.为了方便进行尾插我…

自动化与智能化并行:数字化运维体系助力企业腾飞

文章目录 文章目录 文章目录 一、引言二、数字化运维体系的核心要素三、构建数字化运维体系的策略四、数字化运维体系的实施与挑战主要内容读者对象 一、引言 随着信息技术的迅猛发展&#xff0c;数字化转型已成为企业提升竞争力、实现可持续发展的必由之路。在数字化转型的过…

JSP – 支持WORD上传的富文本编辑器

1.下载示例 https://gitee.com/xproer/zyoffice-tinymce5 2.引入组件 3.配置转换接口 效果 泽优Office文档转换服务(zyOffice) 功能&#xff1a;一键导入Word转HTML&#xff0c;不装控件&#xff0c;不装Office&#xff0c;任意平台兼容(Windows,macOS,Linux,安卓Android,苹果…

Java文件基本操作入门指南

Java文件基本操作入门指南 文章目录 Java文件基本操作入门指南前言一、文件的基本操作1、文件的创建2、文件的写入3、文件的读取4、文件的删除 二、进阶操作与技巧1、文件的复制与移动2、文件内容的追加3、随机访问文件4、文件路径与名称操作 三、最佳实践与注意事项1、异常处理…