【设计模式 03】装饰模式——俄罗斯套娃?

装饰模式(俄罗斯套娃?)

装饰模式:动态的给某些对象添加额外的功能

参考:

  • 简书 | 装饰模式

  • 博客园 | 简说设计模式——装饰模式

  • 博客园 | 装饰器模式 Decorator 结构型 设计模式 (十)

什么是装饰模式

装饰模式也叫装饰器模式,python中的装饰器就是这种模式的体现,对于一个类,如果要添加一个新功能,除了修改代码外(违反开闭原则),可以使用继承,但通过继承添加新功能并不适合所有场景,如

  1. 类不可见或不允许继承
  2. 需要对一批类似的兄弟类添加同一个新功能时,继承会产生大量的子类
  3. 希望新功能的添加和撤销是动态的

装饰模式中的对象包括:

  1. 装饰器(用来为被装饰对象动态添加新功能)

  2. 抽象被装饰对象(所有能被装饰对象的抽象)

  3. 被装饰对象

客户端如果希望给某个对象动态添加一个新功能,就可以把这个对象(被装饰对象)传递给装饰器,由装饰器实现新功能,并保存一个被装饰对象的引用,并返回给客户端一个装饰器对象,这样,被装饰对象原来的行为和属性并没有改变,甚至被装饰对象本身就没有改变,只是在外面套了一个壳子,新功能是这个壳子提供的。就像TCP/IP协议栈中,应用层的数据包到传输层通过加TCP或UDP首部来传输一样。

装饰模式优缺点

优点:

  1. 一个装饰器可以给多个不同的类动态添加新功能
  2. 新功能由装饰器实现,不需要修改被装饰对象,有一定的安全性
  3. 多个装饰器可以配合嵌套使用,以此实现更复杂的功能
  4. 新功能不影响原来的功能,添加和撤销都方便

缺点:

  1. 过多的装饰类可能使程序变得很复杂

  2. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。

    作者:慵懒的阳光丶

适用场景

  1. 要添加的新功能与原有类关联不大时
  2. 新功能需要方便添加和撤销时
  3. 不能或不方便通过继承实现新功能时

比如卖烤冷面,最基本的就是面(抽象被装饰对象)具体的就是烤冷面(被装饰对象),然后可以往面里面加各种配料(抽象装饰器),如鸡蛋,辣条等(具体装饰器),由于不同配料的加入顺序对最后的烤冷面有影响,所以如果要用继承拓展“烤冷面”,那先加鸡蛋再加辣条和先加辣条再加鸡蛋就需要写两个子类,造成冗余重复,这种场景就适合适用装饰模式。

抽象被装饰对象

package pers.junebao.decorator_pattern;public abstract class Noodles {public String rawMaterial;  // 配料public abstract void sayWhoAmI();
}

具体的被装饰对象:

package pers.junebao.decorator_pattern;public class BakedColdNoodles extends Noodles {BakedColdNoodles() {this.rawMaterial = "面";  // 最原始的烤冷面,配料只有面}@Overridepublic void sayWhoAmI() {System.out.println("我是普通烤冷面!");}
}

抽象装饰器:

package pers.junebao.decorator_pattern.decorator;import pers.junebao.decorator_pattern.Noodles;public abstract class Burden extends Noodles {public Noodles noodles;  // 装饰器中保留一份被装饰对象的引用,方便客户端使用public Burden(Noodles noodles) {this.noodles = noodles;}
}
  • 装饰器是为某一类对象提供装饰的(这里就是实现了Noodles 的类)

具体的装饰器类:

  • 加鸡蛋

    package pers.junebao.decorator_pattern.decorator;import pers.junebao.decorator_pattern.Noodles;public class AddEggs extends Burden {public AddEggs(Noodles noodles) {super(noodles);this.rawMaterial = noodles.rawMaterial + ", 鸡蛋";}@Overridepublic void sayWhoAmI() {System.out.println("我是加了鸡蛋的烤冷面!!");}}
    
  • 加辣条

    package pers.junebao.decorator_pattern.decorator;import pers.junebao.decorator_pattern.Noodles;public class AddSpicyStrips extends Burden{public AddSpicyStrips(Noodles noodles) {super(noodles);this.rawMaterial = noodles.rawMaterial + " ,辣条";}@Overridepublic void sayWhoAmI() {System.out.println("我是加了辣条的烤冷面!!");}
    }
    

客户端:

package pers.junebao.decorator_pattern;import pers.junebao.decorator_pattern.decorator.AddEggs;
import pers.junebao.decorator_pattern.decorator.AddSpicyStrips;public class Main {public static void main(String[] args) {Noodles bcn = new BakedColdNoodles();Noodles bcnAddEgg = new AddEggs(bcn);bcnAddEgg.sayWhoAmI();System.out.println(bcnAddEgg.rawMaterial);Noodles bcnEggSpicyS = new AddSpicyStrips(bcnAddEgg);bcnEggSpicyS.sayWhoAmI();System.out.println(bcnEggSpicyS.rawMaterial);}
}
/*
我是加了鸡蛋的烤冷面!!
面, 鸡蛋
我是加了辣条的烤冷面!!
面, 鸡蛋 ,辣条*/

这样如果想先加辣条在家鸡蛋,就可以使用AddSpicyStrips先装饰BakedColdNoodles,再用AddEggs装饰AddSpicyStrips。

GitHub | 完整代码

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

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

相关文章

系统移植的四大步骤

最近在学习系统移植的相关知识,在学习和调试过程中,发现了很多问题,也解决了很多问题,但总是对于我们的开发结果有一种莫名其妙的感觉,纠其原因,主要对于我们的开发环境没有一个深刻的认识,有时…

bem什么意思_bem是什么意思_bem的翻译_音标_读音_用法_例句_爱词霸在线词典

全部Methods Three different concentrations of the n - butanol extract of MOH ( BEM ) : 0.038 g L ~ ( - 1 ), 0.11 g L ~ ( - 1 ) and 0.34 g L ~ ( - 1 ) were prepared.巴戟天醇提取物 ( BEM ) 配成含生药0.038gL~ ( -1)、0.11gL~ ( -1 ) 、 0.34gL~ ( -1 ) 三种浓度…

display:flex

flex:弹性布局 常用属性介绍: flex-direction: column (设置主容器主轴方向) flex-flow: row wrap (第一个参数为flex-direction,第二个为flex-wrap) align-items: flex-start (设…

Linux(Ubuntu 19.10)下 Qt5 连接 MySQL(QMYSQL driver not loaded)

Linux(Ubuntu 19.10)下 Qt5 连接 MySQL 安装好 MySQL 和 Qt Qt 连接 MySQL 的代码 QSqlDatabase dQSqlDatabase::addDatabase("QMYSQL");//加载mysql驱动,这个字符串是固定的 d.setHostName("127.0.0.1"); d.setDatabas…

华为消息推送 有透传通道吗_求解在推送用透传消息-使用厂商通道(我用的是基座测试) 用手机测试出现了“clientId离线”问题...

// #ifdef APP-PLUS// uni.showModal({// title: 提示,// content: 您的用户在其它的app登录,如果有问题,请修改密码或重新登录!,// cancelText:"修改密码",// confirmText:"好的",// success: function (res) {// if (r…

oneuijs/You-Dont-Need-jQuery

oneuijs/You-Dont-Need-jQuery https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.mdYou Dont Need jQuery 前端发展很快,现代浏览器原生 API 已经足够好用。我们并不需要为了操作 DOM、Event 等再学习一下 jQuery 的 API。同时由于 React…

Wpf 数据绑定简介、实例1

简介:1.WPF绑定使用的源属性必须是依赖项属性,这是因为依赖项属性具有内置的更改通知支持,元素绑定表达式使用了Xaml扩展标记, WPF绑定一个控件是使用Binding.ElementName, 绑定非控件对象时使用Source,RelativeSource,DataContex…

【设计模式 04】代理模式

代理模式 代理模式( Proxy):为其他对象提供一种代理以控制对这个对象的访问。 参考:refactoringguru | proxy 什么是代理模式 有时候如果想要访问某个对象,但又没办法直接访问或不方便直接访问,可以使用代理模式,代理…

css 大于号 标签_CSS设计基础选择器篇

点击上方 Java项目学习 ,选择 星标 公众号重磅资讯、干货,第一时间送达前言:如果将CSS样式应用于特定的网页对象上,需要先找到目标元素。在CSS样式中执行这一任务的部分被称为选择器。1 标签选择器优点:为页面中同类型…

CSDN博客投票活动开始了

自己坚持写博客,一方面是为了将自己对知识点的理解做一个总结,另一方面也是因为自己看到了很多无私奉献分享自己知识的小伙伴们,因此自己也想像他们那样尽自己微薄之力把自己对某一知识点的理解分享给大家,或许算不上什么特高级的…

crontab 提示 command not found 解决方案

crontab 提示 command not found 解决方案 今天遇见一个问题,crontab的定时任务会报错:java command not found,但是手动执行脚本一直能成功。 猜想是环境变量的问题。 在crontab里添加个打印环境变量的任务: * * * * * echo $PAT…

java中文乱码decode_Java中文乱码处理

java编码转换过程我们总是用一个java类文件和用户进行最直接的交互(输入、输出),这些交互内容包含的文字可能会包含中文。无论这些java类是与数据库交互,还是与前端页面交互,他们的生命周期总是这样的:1、程序员在操作系统上通过编…

【设计模式 05】工厂方法模式

工厂方法模式 define an interface or abstract class for creating an object but let the subclasses decide which class to instantiate. 参考: refactoringguru | factory-methodjavatpoint | factory-method-design-pattern博客园| 工厂方法 简单工厂的问题 …

[C++]宏定义#define A B C

C关于宏定义的用法,有形如#define A B C的格式,此时B和C都是已知的字符串常量. 在宏定义中. 可以把两个常量字符串连在一起 如果#define A "a" 那么宏定义#define STRING A "bc" 就相当于 #define STRING "abc" 这里&…

LinkedList类源码浅析(二)

1、上一节介绍了LinkedList的几个基本的方法,其他方法类似,就不一一介绍; 现在再来看一个删除的方法:remove(Object o) remove方法接受一个Object参数,这里需要对参数做空与非空处理; 但是删除一个Object元…

【设计模式 06】原型模式(克隆??)

原型模式(clone?) Prototype pattern refers to creating duplicate object while keeping performance in mind. This type of design pattern comes under creational pattern as this pattern provides one of the best ways to create an object. 参考: tutori…

2016OSC源创会年终盛典-综合技术专场-张小刚

2019独角兽企业重金招聘Python工程师标准>>> 综合技术专场 讲师/SPEAKERS 张小刚 网易云负载均衡项目负责人 《网易蜂巢负载均衡技术实践》从网易蜂巢中的实践出发,分享网易蜂巢负载均衡服务从无到有,从私有云到公有云过程中的技术实践。重点…

python策略模式包含角色_详解Python设计模式之策略模式

虽然设计模式与语言无关,但这并不意味着每一个模式都能在每一门语言中使用。《设计模式:可复用面向对象软件的基础》一书中有 23 个模式,其中有 16 个在动态语言中“不见了,或者简化了”。1、策略模式概述策略模式:定义…

mysql 日期

数据类型 数据类型格式date YYYY-MM-DD datetime YYYY-MM-DD HH:MM:SS timestamp YYYY-MM-DD HH:MM:SS year YYYY 或 YY 具体实现的函数 1、now() 返回当前的日期和时间 SELECT NOW(); 2、curdate() 返回当前的日期 SELECT CURdate(); 3、curtime()返回当…

【Go】panic: reflect: call of reflect.Value.FieldByName on ptr Value

产生原因 调用 FieldByName()方法时,调用者与预期类型不相符。 // 错误代码 func setNewArticleInfoToCache(article *Article) {fields : []string{"Title", "Abstract", "ID", "AuthorID", "CreateTime",}im…