设计模式学习(三): 装饰者模式 (附C#实现)
需求
做一个咖啡店的订单系统。
买咖啡时,可以要求加入各种调料,如奶,豆浆,摩卡等。咖啡店会根据调料的不同收取不同的费用。订单系统要考虑这些。
初版设计

然后下面就是所有的咖啡....:

cost方法将计算出咖啡加上各种调料后的价格。
这种方法太笨了。。。必须换一种。
再版设计
使用实例变量和继承!

但是有新的问题:
1.调料价格变化就需要更改现有的代码。
2.一旦出现新的调料,就需要加上新的方法,并改变超类中的cost方法。
3.如果有新的饮料,有些调料可能会不适用。
4.想买双倍的摩卡咖啡怎么办?
设计原则
类应该对扩展开发,对修改关闭。
使用装饰者模式



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

重新设计

C#代码实现
Beverage:
namespace C03DecoratorPattern.Bases
{
public abstract class Beverage
{
protected string Description;
protected Beverage()
{
Description = "Unknown Beverage";
}
public abstract double Cost();
public virtual string GetDescription()
{
return Description;
}
}
}
CondimentDecorator:
namespace C03DecoratorPattern.Bases
{
public abstract class CondimentDecorator : Beverage
{
public abstract override double Cost();
public abstract override string GetDescription();
}
}
咖啡们:
namespace C03DecoratorPattern.Beverages
{
public class Espresso : Beverage
{
public Espresso()
{
Description = "Espresso";
}
public override double Cost()
{
return 1.99;
}
}
}
namespace C03DecoratorPattern.Beverages
{
public class HouseBlend : Beverage
{
public HouseBlend()
{
Description = "House Blend Coffee";
}
public override double Cost()
{
;
}
}
}
调料们:
namespace C03DecoratorPattern.Condiments
{
public class Milk : CondimentDecorator
{
private readonly Beverage _beverage;
public Milk(Beverage beverage)
{
_beverage = beverage;
}
public override double Cost()
{
+ _beverage.Cost();
}
public override string GetDescription()
{
return $"{_beverage.GetDescription()}, Milk";
}
}
}
namespace C03DecoratorPattern.Condiments
{
public class Mocha : CondimentDecorator
{
private readonly Beverage _beverage;
public Mocha(Beverage beverage)
{
_beverage = beverage;
}
public override double Cost()
{
+ _beverage.Cost();
}
public override string GetDescription()
{
return $"{_beverage.GetDescription()}, Mocha";
}
}
}
namespace C03DecoratorPattern.Condiments
{
public class Soy: CondimentDecorator
{
private readonly Beverage _beverage;
public Soy(Beverage beverage)
{
_beverage = beverage;
}
public override double Cost()
{
+ _beverage.Cost();
}
public override string GetDescription()
{
return $"{_beverage.GetDescription()}, Soy";
}
}
}
测试程序:
namespace C03DecoratorPattern
{
class Program
{
static void Main(string[] args)
{
Beverage beverage = new Espresso();
Console.WriteLine($"{beverage.GetDescription()} $ {beverage.Cost()}");
Beverage beverage2 = new HouseBlend();
beverage2 = new Mocha(beverage2);
beverage2 = new Milk(beverage2);
beverage2 = new Soy(beverage2);
Console.WriteLine($"{beverage2.GetDescription()} $ {beverage2.Cost()}");
Console.ReadLine();
}
}
}
运行结果:

设计模式学习(三): 装饰者模式 (附C#实现)的更多相关文章
- 设计模式学习之装饰者模式(Decorator,结构型模式)(16)
参考地址:http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一.定义:装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相 ...
- 设计模式学习心得<装饰器模式 Decorator>
装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装 ...
- Java-马士兵设计模式学习笔记-装饰者模式
Java装饰者模式简介 一.假设有一个Worker接口,它有一个doSomething方法,Plumber和Carpenter都实现了Worker接口,代码及关系如下: 1.Worker.java p ...
- C#设计模式学习之装饰者模式
写这个随笔时,其实对该模式理解的并不是十分透彻.在此想到什么写什么,希望对自己对他人有所帮助. 装饰者模式主要是应用继承和组合的思想,极大的实现了程序的多态,使得的程序有了更高的扩展性. 第一个基础例 ...
- Javascript设计模式学习三(策略模式)
定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换.目的:将算法的使用和算法的实现分离开来.比如: if(input == 'A'){ return 1; } if(input == ...
- 设计模式学习系列6 原型模式(prototype)
原型模式(prototype)用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.允许一个对象再创建另外一个新对象的时候根本无需知道任何创建细节,只需要请求圆形对象的copy函数皆可. 1 ...
- JAVA设计模式之【装饰者模式】
JAVA设计模式之[装饰者模式] 装饰模式 对新房进行装修并没有改变房屋的本质,但它可以让房子变得更漂亮.更温馨.更实用. 在软件设计中,对已有对象(新房)的功能进行扩展(装修). 把通用功能封装在装 ...
- 重学 Java 设计模式:实战装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 对于代码你有编程感觉吗 很多人写代码往往是没有编程感觉的,也就是除了可以把功能按照固 ...
- Java设计模式12:装饰器模式
装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...
随机推荐
- Microsoft Visual Studio | VS打开解决方案时加载失败,或者出现错误提示
Microsoft Visual Studio | VS打开解决方案时加载失败,或者出现错误提示 1.加载失败并且输出状态栏也没什么错误提示的话,往往是因为一个低版本VS2010.VS2012等打开了 ...
- UILabel 的使用
直接上代码: /* UILabel 使用 */ UILabel *aLable = [[UILabel alloc] initWithFrame:self.window.bounds]; aLable ...
- 中小企业为什么要上HR系统
人力资源不不过公司资源.也是一种社会资源. 越来越多的企业已将人作为一种重要的资源来看待,资金和技术则是其次.所以企业内部科学的全面的人力资源管理也因此处在了十分重要的位置上. 现在的人力资源是服务于 ...
- MySQL数据库使某个不是主键的字段唯一
在使用MySQL数据的过程中有时候我们须要某个不是主键的字段不反复.这个时候就要用到SQL的UNIQUE约束了. 以下摘抄自w3school里的一段介绍: UNIQUE 约束唯一标识数据库表中的每条记 ...
- Maven构建真正的J2EE项目
今天同事问起我眼下用Maven构建的多模块项目架构和曾经用Eclipse创建的Web项目的问题.以下将讲一下使用maven搭建多模块的J2ee项目,以及採用这样的方式搭建项目对日后项目的水平拆分和垂直 ...
- Elasticsearch批处理操作——bulk API
Elasticsearch提供的批量处理功能,是通过使用_bulk API实现的.这个功能之所以重要,在于它提供了非常高效的机制来尽可能快的完成多个操作,与此同时使用尽可能少的网络往返. 1.批量索引 ...
- 使用soap实现简单webservice
在网上看到一些关于用soap实现简单webservice的一些知识,简单整理一下希望对大家有所帮助. 可以给大家看一下我的简单实现的列子,Soap,大家可以到Github上自行下载. 首先说一下web ...
- Myeclipse Reload
前言: 在用 myeclipse 做项目开发的时候.如果没有配置热部署,平凡的去启动 server 如果项目小,那么很简单.如果项目很大,那么重启的项目花费的时间会很长. 在 myeclipse 中其 ...
- 《程序设计语言——实践之路【PDF】下载
<程序设计语言--实践之路[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382240 内容简介 <程序设计语言--实践之路(第3版 ...
- ES6之遍历器(Iterator)
什么是Iterator?他是一种接口,为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署上Iterator接口就可以完成遍历操作(PS:个人认为他的这个遍历就是c语言里面的指针),他的作用有 ...