设计模式(七)装饰模式

相关文章
设计模式系列

1.装饰模式简介

装饰模式介绍

装饰模式是结构型设计模式之一,不必改变类文件和使用继承的情况下,动态地扩展一个对象的功能,是继承的替代方案之一。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

定义

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

装饰模式结构图

  • Component:抽象组件,给对象动态的添加职责。
  • ConcreteComponent:组件具体实现类。
  • Decorator:抽象装饰者,继承Component,从外类来拓展Component类的功能,但对于Component来说无需知道Decorator的存在。
  • ConcreteDecorator:装饰者具体实现类。

2.装饰模式的简单实现

装饰模式在现实生活中有很多例子,比如给一个人穿上各种衣服,给一幅画涂色上框等等,这次我要举得例子有些不同,举一个武侠修炼武功的例子:杨过本身就会全真剑法,有两位武学前辈洪七公和欧阳锋分别传授杨过打狗棒法和蛤蟆功,这样杨过除了会全真剑法还会打狗棒法和蛤蟆功。

抽象组件(Component)

作为武侠肯定要会使用武功的,我们先定义一个武侠的抽象类,里面有使用武功的抽象方法:

public abstract class Swordsman {/*** Swordsman武侠有使用武功的抽象方法*/public abstract void attackMagic();
}

组件具体实现类(ConcreteComponent)

被装饰的具体对象,在这里就是被教授武学的具体的武侠,他就是杨过,杨过作为武侠当然也会武学,虽然不怎么厉害:

public class YangGuo extends Swordsman{@Overridepublic void attackMagic() {//杨过初始的武学是全真剑法System.out.println("杨过使用全真剑法");}
}

抽象装饰者(Decorator)

抽象装饰者保持了一个对抽象组件的引用,方便调用被装饰对象中的方法。在这个例子中就是武学前辈要持有武侠的引用,方便教授他武学并“融会贯通”:

public abstract class Master extends Swordsman{private Swordsman mSwordsman;public Master(Swordsman mSwordsman){this.mSwordsman=mSwordsman;}@Overridepublic void attackMagic() {mSwordsman.attackMagic();}
}

装饰者具体实现类(ConcreteDecorator)

这个例子中用两个装饰者具体实现类,分别是洪七公和欧阳锋,他们负责来传授杨过新的武功:

public class HongQiGong extends Master {public HongQiGong(Swordsman mSwordsman) {super(mSwordsman);}public void teachAttackMagic(){System.out.println("洪七公教授打狗棒法");System.out.println("杨过使用打狗棒法");}@Overridepublic void attackMagic() {super.attackMagic();teachAttackMagic();}
}
public class OuYangFeng extends Master {public OuYangFeng(Swordsman mSwordsman) {super(mSwordsman);}public void teachAttackMagic(){System.out.println("欧阳锋教授蛤蟆功");System.out.println("杨过使用蛤蟆功");}@Overridepublic void attackMagic() {super.attackMagic();teachAttackMagic();}
}

 客户端调用

经过洪七公和欧阳锋的教导,杨过除了初始武学全真剑法又学会了打狗棒法和蛤蟆功:

 

public class Client {public static void main(String[] args){//创建杨过YangGuo mYangGuo=new YangGuo();//洪七公教授杨过打狗棒法,杨过会了打狗棒法HongQiGong mHongQiGong=new HongQiGong(mYangGuo);mHongQiGong.attackMagic();//欧阳锋教授杨过蛤蟆功,杨过学会了蛤蟆功OuYangFeng mOuYangFeng=new OuYangFeng(mYangGuo);mOuYangFeng.attackMagic();}
}

3.装饰模式的优缺点和使用场景

优点
  • 通过组合而非继承的方式,动态的来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。
  • 有效避免了使用继承的方式扩展对象功能而带来的灵活性差,子类无限制扩张的问题。
  • 具体组件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体组件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。
缺点
  • 装饰链不能过长,否则会影响效率。
  • 因为所有对象都是继承于Component,所以如果Component内部结构发生改变,则不可避免地影响所有子类(装饰者和被装饰者),如果基类改变,势必影响对象的内部。
  • 比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐,所以只在必要的时候使用装饰者模式。
使用场景
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 需要动态地给一个对象增加功能,这些功能可以动态的撤销。
  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

4.装饰模式和代理模式

在上一篇文章设计模式之代理模式中我们讲到了代理模式,你会觉得代理模式和装饰模式有点像,都是持有了被代理或者被装饰对象的引用。它们两个最大的不同就是装饰模式对引用的对象增加了功能,而代理模式只是对引用对象进行了控制却没有对引用对象本身增加功能。

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

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

相关文章

《TCP/IP详解 卷一》第7章 防火墙和NAT

7.1 引言 NAT通常改变源IP和源端口,不改变目的IP和目的端口。 7.2 防火墙 常用防火墙: 包过滤防火墙(packet-filter firewall) 代理防火墙(proxy firewall) 代理防火墙作用: 1. 通过代理服务…

【Java EE初阶二十三】servlet的简单理解

1. 初识servlet Servlet 是一个比较古老的编写网站的方式,早起Java 编写网站,主要使用 Servlet 的方式,后来 Java 中产生了一个Spring(一套框架),Spring 又是针对 Servlet 进行了进一步封装,从而让我们编写网站变的更简单了;Sprin…

JavaScript函数默认参数

首先我们写一个简单的预订功能; use strict; const bookings [];const createBooking function (flightNum, numPassengers, price) {const booking {flightNum,numPassengers,price,};console.log(booking);bookings.push(booking); };createBooking(LH123);●…

图像读取裁剪与人脸识别

图像读取 Image read ⇒ \Rightarrow ⇒ torchvision.datasets from torchvision import datasets dataset datasets.ImageFolder(data_dir, transformtransforms.Resize((512, 512)))Return value illustration dataset[0][0]是PIL.Image objects,这利用IPyth…

这几个Python内置函数你都知道吗

divmod() divmod() 是一个 Python 内置函数,用于同时返回商和余数。它接受两个参数,第一个参数是被除数,第二个参数是除数,返回一个包含两个值的元组,第一个值是商,第二个值是余数。 示例用法如下&#…

支持向量机|机器学习方法(李航)

支持向量机,可以看着是升级版的感知机,与感知机相比。他们都是找到一个超平面对数据集进行分割,区别在于,感知机模型得到的超平面空间中可以有无穷个超平面,但支持向量机仅含有一个,这一个超平面与样本点的…

堆/堆排序(C/C++)

本篇文章将会较为全面的介绍堆的概念以及实现堆两个重要算法:向上调整算法和向下调整算法。接着实现了堆排序。 若想查看对应位置,可直接按照以下目录进行查看: 目录 1.堆的概念及结构 2.堆的实现 2.1 堆的向上调整算法 2.2 堆的向下调整算法…

【代码随想录python笔记整理】第十三课 · 链表的基础操作 1

前言:本笔记仅仅只是对内容的整理和自行消化,并不是完整内容,如有侵权,联系立删。 一、链表 在之前的学习中,我们接触到了字符串和数组(列表)这两种结构,它们具有着以下的共同点:1、元素按照一定的顺序来排列。2、可以通过索引来访问数组中的元素和字符串中的字符。由此,…

力扣模板题:回文链表

请牢记检测回文串的模板 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/ bool isPalindrome(struct ListNode* head) {int size0;struct ListNode* pointhead;while(point){size;pointpoint->next;}int arr…

微信小程序本地开发

微信小程序本地开发时不需要在小程序后台配置服务器域名直接在小程序项目中填写后端在本机的IP地址和端口号 如图(第一步) 填写地址后发现报错,url不是合法域名,则在详情设置不校验合法域名 如图(第二歩)…

学习vue3第二节(使用vite 创建vue3项目)

使用vite 创建vue3项目 node 安装请移步 node官网: https://nodejs.p2hp.com/ node 版本控制 请移步 nvm官网:https://nvm.uihtm.com/ vite 生成vue项目完整版 请移步 vite官网:https://cn.vitejs.dev/ 1、使用 npm 或者 yarn 创建vue3 项目…

9.网络游戏逆向分析与漏洞攻防-游戏网络架构逆向分析-接管游戏连接服务器的操作

内容参考于:易道云信息技术研究院VIP课 上一个内容:游戏底层功能对接类GameProc的实现 码云地址(master 分支):https://gitee.com/dye_your_fingers/titan 码云版本号:44c54d30370d3621c1e9ec3d7fa1e2a0…