设计模式学习(三): 装饰者模式 (附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)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...
随机推荐
- less新手入门(二) Mixin 混合、带参数的Mixin
四.mixin 混合 "mix - in"属性来自现有的样式!! 你可以在类选择器和id选择器中使用mixin, .a,#b{ color: rebeccapurple; } . ...
- HDU 2298 Toxophily(公式/三分+二分)
Toxophily Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- Android后台执行的定时器实现
Android后台运行定时器,方便我们运行定位跟踪等任务需求. 以下简要说明实现Android后台定时器的要点, 文章末尾能够下载到project代码,可直接编译运行. AndroidManifest ...
- 简单了解Markdown
在Github的readme.md文件的编辑中,開始渐渐的接触Markdown.如今简单系统叙述一下Markdown的语法. Markdown是一种能够使用普通文本编辑器编写的标记语言.通过类似HTM ...
- Hibernate学习笔记(五) — 多对多关系映射
多对多关系映射 多对多建立关系相当于在第三张表中插入一行数据 多对多解除关系相当于在第三张表中删除一行数据 多对多改动关系相当于在第三张表中先删除后添加 多对多谁维护效率都一样.看需求 在实际开发过程 ...
- 用泛型创建SqlServerHelper类实现增删改查(一)
使用泛型,可以构建对数据库单表的基本增删改查. 首先有一数据库 Test_SqlServerHelper ,有2表 接下来创建项目,对数据库进行增删改查. 直接贴代码:(SqlServerHelper ...
- Docker 搭建 etcd 集群
阅读目录: 主机安装 集群搭建 API 操作 API 说明和 etcdctl 命令说明 etcd 是 CoreOS 团队发起的一个开源项目(Go 语言,其实很多这类项目都是 Go 语言实现的,只能说很 ...
- cookie和session(一)
先来谈谈我对session和cookie的理解,事实上,只要你去面试web开发,面试官十有八九会问这个问题. cookie和session经常被放在一起问,其实在我看来这两个东西完全是两个不一样的. ...
- gunicorn 信号处理(SIGHUP,SIGUSR2)
在这篇文章中,提到了Master进程对信号的处理函数,其中有两个信号比较有意思. SIGHUP:用来热更新(Reload)应用 SIGUSR2:用来在线升级(upgrade on the fly)gu ...
- VMware安装Linux,系统分区。
系统分区: 主分区<=4 扩展分区<=1 主分区+扩展分区<=4 扩展分区不能直接使用,必须再分成若干逻辑分区才能读写数据. 逻辑分区编号从5开始,1-4给主分区和扩展分区使用的,不 ...