设计模式篇——初探装饰器模式
文章目录
1、装饰器模式介绍
2、装饰器模式类图
3、装饰器模式Demo实现(一个小镇的拉面馆)
4、装饰器模式总结
装饰器模式介绍:装饰器模式可以在不修改任何底层代码的情况下,给对象赋予新的职责(程序运行时的扩展,动态的将责任附加到对象上)。属于结构型设计模式。
类图:
我们来看下装饰器模式的类图:
一个简单的Demo(故乡小镇的一个面馆):
在故乡的一个小镇上面,有一家面馆,主营拉面。在这里你可以只点清汤面(SoupNoodle),也可以往里面加佐料,佐料有牛肉(Beef),鱼丸(FishBall)还有菠菜(Spinach)。面馆今天开张了。
这里的所有面条都基于一个抽象类BaseNoodle来实现,这个抽象类有两个抽象方法,获取它的价格(double Price()),获取它的名字(string GetName())。
1 /// <summary> 2 /// 面条抽象类 3 /// </summary> 4 public abstract class BaseNoodle 5 { 6 /// <summary> 7 /// 价格 8 /// </summary> 9 /// <returns></returns> 10 public abstract double Price(); 11 /// <summary> 12 /// 获取名称 13 /// </summary> 14 /// <returns></returns> 15 public abstract string GetName(); 16 }
BaseNoodle
然后让我们实现下我们最基础的清汤面(SoupNoodle),清汤面的价格是1块钱(嗯,还蛮实惠的)
1 /// <summary> 2 /// 清汤面 3 /// </summary> 4 public class SoupNoodle : BaseNoodle 5 { 6 private static double cost = 1; 7 public override string GetName() 8 { 9 return "清汤面"; 10 } 11 public override double Price() 12 { 13 return cost; 14 } 15 }
SoupNoodle
这时候,我们来了第一位客人(张三),他要一碗带牛肉作料的清汤面
于是乎,我们就实现了这样一个类。
1 public class SoupNoodleWithBeef : BaseNoodle 2 { 3 private static double cost = 1; 4 public override string GetName() 5 { 6 return "清汤面" + ",牛肉"; 7 } 8 /// <summary> 9 /// 假设牛肉一份0.6元 10 /// </summary> 11 /// <returns></returns> 12 public override double Price() 13 { 14 return cost + 0.6; 15 } 16 }
SoupNoodleWithBeef
然后第二个客人进来了,是个可爱的小姑娘,她要一份加菠菜的清汤面。于是乎,我们又要实现这样一个类。
1 public class SoupNoodleWithSpinach : BaseNoodle 2 { 3 private static double cost = 1; 4 public override string GetName() 5 { 6 return "清汤面" + ",菠菜"; 7 } 8 /// <summary> 9 /// 假设菠菜一份0.2元 10 /// </summary> 11 /// <returns></returns> 12 public override double Price() 13 { 14 return cost + 0.2; 15 } 16 }
SoupNoodleWithSpinach
我们一共有三种佐料,假设客人的口味都不同,那样的话我们需要多少个继承自BaseNoodle的子类呢? 没错,应该是A(3,3)个6个子类。这样显然不行,假如我们后期有添加了新的佐料,虾球,那样我们的子类个数就是24个,况且谁又能保证客人只点一份相同的佐料呢?假如点两份牛肉呢?我们的子类个数将呈现指数级别的增长。。。
这时候我们的装饰器模式就登场了。
还是我们的面条基类抽象类,和清汤面(被装饰者)类,在这个的基础之上我们将不再写很多针对细节的子类。我们首先实现一个佐料抽象类(SeasoningDecorator),这个抽象类也要继承自BaseNoodle。它内部有一个实例变量=》BaseNoodle
1 /// <summary> 2 /// 基础佐料类 3 /// </summary> 4 public abstract class SeasoningDecorator : BaseNoodle 5 { 6 private BaseNoodle _baseNoodle = null; 7 public SeasoningDecorator(BaseNoodle baseNoodle) 8 { 9 _baseNoodle = baseNoodle; 10 } 11 12 public override string GetName() 13 { 14 return this._baseNoodle.GetName(); 15 } 16 17 public override double Price() 18 { 19 return this._baseNoodle.Price(); 20 } 21 }
SeasoningDecorator
此时,我们定义我们的具体佐料类,这些佐料类都继承自SeasoningDecorator,而且内部都存在一个实例变量=》BaseNoodle。
1 /// <summary> 2 /// 牛肉 3 /// </summary> 4 public class BeefDecorator: SeasoningDecorator 5 { 6 private static double cost = 0.6; 7 private BaseNoodle _baseNoodle = null; 8 public BeefDecorator(BaseNoodle baseNoodle) : base(baseNoodle) 9 { 10 _baseNoodle = baseNoodle; 11 } 12 public override string GetName() 13 { 14 return this._baseNoodle.GetName() + ",牛肉"; 15 } 16 public override double Price() 17 { 18 return this._baseNoodle.Price() + cost; 19 } 20 }
BeefDecorator
1 /// <summary> 2 /// 鱼丸 3 /// </summary> 4 public class FishBallDecorator : SeasoningDecorator 5 { 6 private static double cost = 0.4; 7 private BaseNoodle _baseNoodle = null; 8 public override string GetName() 9 { 10 return this._baseNoodle.GetName() + ",鱼丸"; 11 } 12 public FishBallDecorator(BaseNoodle baseNoodle) : base(baseNoodle) 13 { 14 _baseNoodle = baseNoodle; 15 } 16 public override double Price() 17 { 18 return this._baseNoodle.Price() + cost; 19 } 20 }
FishBallDecorator
1 /// <summary> 2 /// 菠菜 3 /// </summary> 4 public class Spinach : SeasoningDecorator 5 { 6 private static double cost = 0.2; 7 private BaseNoodle _baseNoodle = null; 8 public override string GetName() 9 { 10 return this._baseNoodle.GetName() + ",菠菜"; 11 } 12 public Spinach(BaseNoodle baseNoodle) : base(baseNoodle) 13 { 14 _baseNoodle = baseNoodle; 15 } 16 public override double Price() 17 { 18 return this._baseNoodle.Price() + cost; 19 } 20 }
Spinach
这些具体的佐料类就是我们的装饰器。因为它构造函数接收一个BaseNoodle,所以我们可以这样来实现对清汤面(SoupNoodle)的装饰:
1 //定义清汤面 2 BaseNoodle baseSoupNoodle = new SoupNoodle(); 3 //添加一份牛肉 4 baseSoupNoodle = new BeefDecorator(baseSoupNoodle); 5 //添加一份鱼丸 6 baseSoupNoodle = new FishBallDecorator(baseSoupNoodle); 7 //添加一份菠菜 8 baseSoupNoodle = new Spinach(baseSoupNoodle); 9 //再添加一份牛肉 10 baseSoupNoodle = new BeefDecorator(baseSoupNoodle); 11 Console.WriteLine($"点了一份{baseSoupNoodle.GetName()},价格为{baseSoupNoodle.Price()}"); 12 Console.Read();
点餐
装饰器模式总结:
- 装饰器属于结构型设计模式,很好的遵循了开闭原则。
- 装饰器模式的装饰者与被装饰者有相同的超类型。
- 装饰器模式可以在程序运行时,以组合的方式,动态的给对象添加行为(因为有相同的超类型,所以任何需要原始对象的场合,都可以用装饰过的对象去替代它)。
- 装饰器模式会出现很多的小的类型。
转载于:https://www.cnblogs.com/liumengchen-boke/p/8725812.html
设计模式篇——初探装饰器模式相关推荐
- 设计模式之【装饰器模式】
和表妹去喝奶茶 表妹:哥啊,我想喝奶茶. 我:走啊,去哪里喝? 表妹:走,我带你去,我经常去的那家,不但好喝,还可以自由搭配很多小料.我每次都是不同的搭配,换着喝,嘻嘻. 我:你倒是挺会喝的嘛~ 你看 ...
- 大聪明教你学Java设计模式 | 第七篇:装饰器模式
前言 大聪明在写代码的过程中发现设计模式的影子是无处不在,设计模式也是软件开发人员在软件开发过程中面临的一般问题的解决方案.大聪明本着"独乐乐不如众乐乐"的宗旨与大家分享一下设计模 ...
- Java设计模式12:装饰器模式
装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...
- java中装饰器_Java设计模式12:装饰器模式
装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...
- 《设计模式》之装饰器模式
一.什么是装饰器模式 当需要对类的功能进行拓展时,一般可以使用继承,但如果需要拓展的功能种类很繁多,那势必会生成很多子类,增加系统的复杂性,并且使用继承实现功能拓展时,我们必须能够预见这些拓展功能,也 ...
- Java设计模式之《装饰器模式》及应用场景
一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是单方,和代理模式相同,而且目标必须是抽象的. 而实际上,装饰器模式和代理模式 ...
- Java设计模式之《装饰器模式》
一.概述 装饰器模式作用是针对目标方法进行增强,提供新的功能或者额外的功能. 不同于适配器模式和桥接模式,装饰器模式涉及的是单方,和代理模式相同,而且目标必须是抽象的. 而实际上,装饰器模式和代理模式 ...
- 【Java设计模式系列】装饰器模式(Decorator Pattern)
简介 一般有两种方式可以给一个类或对象新增行为: 继承 子类在拥有自身方法同时还拥有父类方法.但这种是静态的,用户无法控制增加行为的方式和时机. 关联 将一个类的对象嵌入另一个对象,由另一个对象决定是 ...
- 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!
最新文章
- git remote添加其他SSH端口
- 宜昌高新区三峡云计算机大楼,【智慧宜昌】CREATOR快捷CS分布式系统成功入驻三峡云计算中心...
- Objective-C语法之字符串NSString去掉前后空格或回车符(可以是NSCharacterSet类型的其它字符)...
- 欢乐纪中A组周六赛【2019.5.18】
- python做自动化控制postman_使用postman+newman+python做接口自动化测试
- docker 守护进程
- sqlyog通过跳板机ssh连接mysql数据库
- Java中 IO 常用操作
- 计算机网络原理的思维导图汇总
- PMP考试题型是如何分布的?
- Hadoop和Hbase版本选择
- C++整数快速读写模板(快速读入+快速写)详解
- 怎么用超级文档免费制作调查问卷
- 有想法阿里系工作的么?各个事业群,都可以挑选。
- Leetcode 32 最长合法括号子序列
- windows 中NET 命令的使用
- 计算机操作系统复习资料
- 如何利用eclipse的WTD自动部署一个webservice
- 最高检发布破坏计算机信息系统案等六大指导性案例
- 你与心中“小仙女”的距离 只差一个海马体照相馆
热门文章
- 【CyberSecurityLearning 62】文件包含
- docker 上关于hyper-v和wsl2的一些要点
- 25匹马,找出最快的3匹,但是只有5个赛道,每次比赛只能得到5匹马的速度排序,那么最少需要多少次比赛
- 都2021年了,不会还有人连深度学习都不了解吧(一)- 激活函数篇
- 1060 Are They Equal
- Leetcode-单调数列(896)
- 10 Lessons Learned Doing ICOs
- Part 1 – Reverse engineering using Androguard
- Android的IPC机制Binder
- 学java的正确方法_学习Java编程 这10个技巧不容错过--中享思途