原文:[Head First设计模式]山西面馆中的设计模式——装饰者模式

引言

在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式。这里也就依葫芦画瓢,换汤不换药的用装饰者模式来模拟一碗鸡蛋面是怎么出来的吧。吃货有吃货的方式来理解......这里先将书中讲到的例子放在前面,理论的东西,讲的还是比较具体的,只是觉得咖啡的例子不是太好理解,lz很土,几乎没喝过咖啡,不知道什么摩卡啊......,还是中国特色的例子更好理解。

为什么学设计模式?

答:觉得会设计模式的人,不仅仅是码农,更像艺术家!

为什么现在学设计模式?

答:不求精通,但求认识,接触过不少项目,有设计模式,而不认识,是我的损失,体会不到他的妙处,但不求它认识我。

装饰者到底装饰谁呢?

类,还是对象?

装饰者模式定义

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。(由定义可知,装饰对象的)

实例分析

星巴兹咖啡订单管理系统 管理、计算各种饮料的售价。

若顾客根据个人喜好,添加不同的调料,那么系统就要有根据调料的不同来计算价格,按照原来的设计,必定会出现下面的情况。

第一种方案设计:继承

有多少种口味的咖啡,你就得建多少种对应的类。烦不?

第二种方案设计:

思考

当哪些因素改变时会影响这个设计?

调料价钱的改变会使我们更改现有代码。

一旦出现新的调料,我们就需要加上新的方法,并改变超类中的cost()方法。

以后可能会开发出新饮料,对于这些饮料而言(冰茶),某些调料可能并不适合,但是在这个设计方式中,Tea子类仍将继承那些不合适的方法,比如:hasWhip()。
如何顾客想要双倍摩卡,怎么办?

......

设计原则(Open-Closed Principle)

类应该对扩展开放,对修改关闭。

我们的目标是允许类容易扩展,在不修改现有代码的情况下,就可搭配新的行为。如能实现这样的目标,其好处在于:这样的设计具有弹性,可以应对改变,可以接受新的功能来应对改变的需求。

如何让设计的每个部分都遵循开放-关闭原则?

这通常是无法做到的。要让OO设计同时具有开放性和关闭性,又不修改现有的代码,需要花费许多时间和努力。一般来说,我们没有足够的精力把设计的每个部分都这么设计,这可能只是一种浪费。
遵循开放-关闭原则,通常会引入新的抽象层次,增加代码的复杂度。你需要把注意力集中在设计中最有可能改变的地方,然后应用开放-关闭原则。

装饰者模式

星巴兹咖啡订单管理系统——使用装饰者模式

以饮料(Beverage)为主体,然后在运行时以调料(Condiment)来装饰(decorate)饮料

比如,顾客想要摩卡和奶泡深焙咖啡,那么:
取出一个深焙咖啡(DarkRoast)对象
以摩卡(Mocha)对象装饰它
以奶泡(Whip)对象装饰它
调用cost方法,并依赖委托(delegrate)将调料的价格加上去

步骤:

“装饰者模式”——特点

装饰者和被装饰对象具有相同的超类型
可以用一个或多个装饰者包装一个对象
由于装饰者和被装饰对象有相同的超类型,所以在任何需要原始对象(被包装)的场合,都可以用装饰过的对象代替她
装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的
对象可以在任何时候被装饰,所以可以在运行时动态的、不限量的用需要的装饰者来装饰对象

装饰者模式类图关系

星巴兹咖啡销售系统装饰者模式类图关系

思考:为什么Decorate类扩展自Component类?

装饰者和被装饰者必须是一样的类型,我们在此使用继承达到“类型匹配”
类型匹配意味着装饰者和被装饰者具有相同的接口,从而装饰者可以取代被装饰者
新的行为并不是继承自超类,而是由组合对象得到,即所有饮料和调料可以更有弹性的加以混合和匹配
我们可以在任何时候,实现新的装饰者增加新的行为。如果依赖继承,每当需要新行为时,必须修改代码
Component类型可以使用抽象类,也可以使用接口

问题:如果有一张订单:“双倍摩卡豆浆奶泡拿铁咖啡”,应该如何进行设计?

这里代码的具体实现就不再写了,网上这样的代码太多了?

山西面馆中的“装饰者模式”

先上类图:直观形象

 代码实现:

 1      /// <summary>
 2     ///抽象类 食物基类 其他类都继承自该类
 3     /// </summary>
 4     public abstract class Food
 5     {
 6         protected string description = "未知的饭";
 7         public virtual string GetDescription()
 8         {
 9             return this.description;
10         }
11         public abstract double Cost();
12     }

1       /// <summary>
2     /// 所有配料的基类 继承自Food类 保持类型一致
3     /// </summary>
4     public abstract class Ingredients : Food
5     {
6
7     }

具体的配料:鸡蛋,西红柿类继承配料类

 1 public class Egg : Ingredients
 2     {
 3         Food meal;
 4         public Egg(Food meal)
 5         {
 6             this.meal = meal;
 7
 8         }
 9         public override double Cost()
10         {
11             return 3.0 + meal.Cost();
12         }
13
14         public override string GetDescription()
15         {
16             return "鸡蛋"+meal.GetDescription();
17         }
18     }

 1 public class Tomato : Ingredients
 2     {
 3         Food meal;
 4         public Tomato(Food meal)
 5         {
 6             this.meal = meal;
 7
 8         }
 9         public override double Cost()
10         {
11             return 3.0 + meal.Cost();
12         }
13
14         public override string GetDescription()
15         {
16             return "西红柿" + meal.GetDescription();
17         }
18     }

所谓的component类(Noodle)继承自Food类

 1   public class Noodle : Food
 2     {
 3         public Noodle()
 4         {
 5             description = "面";
 6         }
 7         public override double Cost()
 8         {
 9             return 3.0;
10         }
11     }

控制台测试程序:

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //创建被装饰的对象 noodle
 6             Food f1 = new Noodle();
 7             //用鸡蛋装饰
 8             f1 = new Egg(f1);
 9             //用西红柿装饰
10             f1 = new Tomato(f1);
11             Console.WriteLine(f1.GetDescription() + "\t" + f1.Cost() + "¥");
12             Console.Read();
13         }
14     }

结果:

思考:装饰者模式是否对修改封闭,对扩展开放呢?

那么,测试一下,加入现在我想要一份酱爆鸡丁盖浇饭,该怎么实现?

 1  public class Rice : Food
 2     {
 3         public Rice()
 4         {
 5             description = "盖浇饭";
 6         }
 7         public override double Cost()
 8         {
 9             return 5.0;
10         }
11     }

 1  public class Chicken : Ingredients
 2     {
 3         Food meal;
 4         public Chicken(Food meal)
 5         {
 6             this.meal = meal;
 7         }
 8         public override string GetDescription()
 9         {
10             return "酱爆鸡丁" + meal.GetDescription();
11         }
12         public override double Cost()
13         {
14             return 9.0 + meal.Cost();
15         }
16     }

 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             //创建被装饰的对象 noodle
 6             Food f1 = new Noodle();
 7             //用鸡蛋装饰
 8             f1 = new Egg(f1);
 9             //用西红柿装饰
10             f1 = new Tomato(f1);
11             Console.WriteLine(f1.GetDescription() + "\t" + f1.Cost() + "¥");
12             //创建被装饰的对象 米饭
13             Food f2 = new Rice();
14             //用酱爆鸡丁 装饰(将配料合并了)
15             f2 = new Chicken(f2);
16             Console.WriteLine(f2.GetDescription() + "\t" + f2.Cost() + "¥");
17             Console.Read();
18         }
19     }

结果:

很容易扩展吧?只需要加两个类继承对应的类就可以了,原来的内部代码不需要修改,就可以实现

总结

在我们的代码中,应该允许行为遵循对扩展开放-对修改关闭的原则,这样就可以无需修改现有的代码就可以实现我们扩展的功能。

装饰者模式意味着一群装饰者类,这些类用来包装具体组件。

装饰者反映出被装饰者的组件类型(具有相同的类型)

装饰者可以在被装饰者的行为前面或后面加上自己的行为,甚至将被装饰者的行为整个取代,而达到特定的目的。

可以用无数个装饰者包装一个组件。

装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。

装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂。

(最近一直在看设计模式,上班下班的路上想,吃饭的时候也想,不求精通,只求在项目中遇到了,能认出他,不求他认识我)

参考书:

Head First 设计模式

[Head First设计模式]山西面馆中的设计模式——装饰者模式相关推荐

  1. [Head First设计模式]山西面馆中的设计模式——观察者模式

    原文:[Head First设计模式]山西面馆中的设计模式--观察者模式 系列文章 [Head First设计模式]山西面馆中的设计模式--装饰者模式 引言 不知不自觉又将设计模式融入生活了,吃个饭也 ...

  2. 设计模式在Netty中的应用-装饰者模式源码举例

    装饰者模式要点回顾: 1.装饰者和被装饰者实现同一个接口. 2.装饰者通常继承被装饰者,同宗同源. 3.动态修改.重载被装饰者的方法. WrappedByteBuf : class WrappedBy ...

  3. 【设计模式】汉堡中的设计模式——模板方法

    艺术来源于生活,有时候灵感真的就在那么一瞬间 看到上图这个板烧没有,这就是我今晚的晚餐了:走进麦当劳里面,有很多很多的汉堡 板烧鸡腿堡.麦辣鸡腿堡.麦香堡.深海鳕鱼堡- 这些个汉堡的制作方式,似乎有着 ...

  4. Java设计模式(3 / 23):装饰者模式

    文章目录 定义 案例1:三点几啦 首次尝试 再次尝试 设计原则:类应该对扩展开放,对修改关闭 尝用装饰者模式 装饰者模式特征 本例的类图 放码过来 饮料类 HouseBlend DarkRoast E ...

  5. 【设计模式十六之装饰模式】装饰者模式

    Decorator Pattern装饰模式 细说装饰模式 细说装饰模式 定义 UML模型 场景 场景一 场景二 代码 代码一 代码二 基于UML的代码 装饰模式应用和注意事项 细说装饰模式 提示: 博 ...

  6. java/android 设计模式学习笔记(7)---装饰者模式

    这篇将会介绍装饰者模式(Decorator Pattern),装饰者模式也称为包装模式(Wrapper Pattern),结构型模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时它也是 ...

  7. 《Head First设计模式》第三章笔记 装饰者模式

    装饰者模式(Decorator Pattern) *利用组合(composition)和委托(delegation)可以在运行时实现继承行为的效果,动态地给对象加上新的行为. *利用继承扩展子类的行为 ...

  8. 设计模式系列【24】:装饰器模式(装饰设计模式)详解

    上班族大多都有睡懒觉的习惯,每天早上上班时间都很紧张,于是很多人为了多睡一会,就会用方便的方式解决早餐问题.有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么"加码&quo ...

  9. 设计模式学习笔记(三)-装饰者模式

    定义 装饰者模式:在不改变原类文件以及不使用继承的情况下,动态地将责任附加到对象上,从而实现动态拓展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 设计原则 要使用装饰者模式, ...

最新文章

  1. 外包公司做遗留项目有意思么?
  2. 第3周实践项目3 求集合并集
  3. 在python中如何比较两个float类型的数据是否相等
  4. 我的爹,我的娘(2006-02-22 21:39:07)(新浪)
  5. rhel Linux 网络配置
  6. Java并发编程笔记—摘抄—基础知识
  7. 贝格数据携手清华大学“勘探”大数据富矿
  8. linux下imp导入oracle数据库,Oracle数据库Linux下的导入IMP
  9. 【图像融合】基于matlab CBF算法图像融合【含Matlab源码 083期】
  10. java解码acc音频文件_g711a音频文件转aac格式
  11. python体重转换_Python第十二课 计算体脂率2.0
  12. 笔记本电脑无法进入睡眠状态_电脑进入睡眠模式后打不开屏幕怎么办
  13. oracle递归查询用法
  14. 国开电大 钢--混凝土组合结构 形成性考核1-4
  15. inline内联函数 static静态函数 普通函数区别
  16. python中size的用法.dim_【Numpy库学习笔记】Numpy中dim、shape和size的理解
  17. UE4-VaRest插件
  18. Java师说CMS管理系统源码
  19. springboot 后台管理系统源码
  20. 账套输出时文件服务器错误,你为什么会创建账套失败?

热门文章

  1. 不要一辈子都指望用技术赚钱
  2. 从字符串中提取BCD码,转换为UINT数据并返回
  3. LR中的吞吐量与响应时间
  4. WIN7盗版的警告!你见过吗?
  5. android开机自动运行程序
  6. idea_pyspark 环境配置
  7. 使项目持续集成支持Carthage管理
  8. 解除织梦dedeCMS标题/关键词/ 简略标题长度限制听语音
  9. HTTP 错误 404.0 - Not Found 您要找的资源已被删除、已更名或暂时不可用。
  10. PowerShell图形化编程1-原理