装饰者模式 Decorator
项目:咖啡计费系统
背景:现有系统中有一个抽象类Beverage,有2个抽象方法GetDescription和Cost。
namespace DecoratorPattern
{
/// <summary>
/// 饮料抽象类
/// </summary>
public abstract class Beverage
{
protected string description = "饮料";
protected float price = 0f;
public abstract string GetDescription(); public abstract float Cost();
}
}
需求:目前有综合咖啡、深焙咖啡、浓缩咖啡,调料有牛奶、摩卡、豆浆、奶泡。未来可能增加新的咖啡种类和调料,当顾客点咖啡时,要求能够获得咖啡的描述和价格。
设计方案1:设计综合咖啡、深焙咖啡、浓缩咖啡4个子类,继承Beverage。再用这4个子类分别派生4个子类,带有牛奶的综合咖啡,带有摩卡的综合咖啡,带有豆浆的综合咖啡...
分析:缺点时显而易见的,这样做导致“类爆炸”,一共需要3*4=12个子类。
设计方案2:把调料作为咖啡的属性设置在Beverage里,并增加方法HasMilk(),SetMilk()等类似的方法。
分析:缺点这样做无疑时从一个灾难跳进另一个灾难中。我们在开发中应当尽量避免修改已有代码,遵循“开闭原则”。而且当增加新的饮料时,又要修改基类。
另一个灾难是,子类在计算价格时,需要大量的分支结构来判断是否包含某种调料,以计算咖啡的价格,我们总是尽量的避免复杂的分支结构,这使得维护变得非常困难。
还有针对实现编程带来的问题,不能够动态的添加职责。
装饰者模式 Decorator 闪亮登场:
装饰者模式动态的将职责附加到对象上。若要扩展共呢个,装饰者提供了比继承更有弹性的替代方案。
1. 4个基类继承Beverage
namespace DecoratorPattern
{
/// <summary>
/// 综合咖啡
/// </summary>
public class HouseBlend:Beverage
{
public HouseBlend(float price)
{
this.price = price;
this.description = "综合咖啡";
} public override float Cost()
{
return price;
}
public override string GetDescription()
{
return this.description;
}
}
}
namespace DecoratorPattern
{
/// <summary>
/// 深焙咖啡
/// </summary>
public class DarkRoast:Beverage
{
public DarkRoast(float price)
{
this.price = price;
this.description = "深焙咖啡";
}
public override string GetDescription()
{
return this.description;
}
public override float Cost()
{
return price;
}
}
}
namespace DecoratorPattern
{
/// <summary>
/// 浓缩咖啡
/// </summary>
public class Espresso:Beverage
{
public Espresso(float price)
{
this.price = price;
this.description = "浓缩咖啡";
}
public override float Cost()
{
return this.price;
}
public override string GetDescription()
{
return this.description;
}
}
}
装饰者继承Beverage,注意这里继承的目的并不是为了获得基类的功能,而是为了类型匹配,达到多态的目的,获得功能由组合来实现。因此每一个装饰者都需要维护一个Beverage引用。
namespace DecoratorPattern
{
/// <summary>
/// 摩卡装饰者,为了能够取代Beverage,所以CondimentDecorator继承自Beverage,目的并非获得Beverage
/// 而是为了类型匹配
/// </summary>
public class Mocha : Beverage
{
//持有抽象类饮料的引用,达到运行时添加职责的目的
Beverage beverage;
//包装Beverage
public Mocha(Beverage b, float price)
{
beverage = b;
this.price = price;
}
public override float Cost()
{
return beverage.Cost() + price;
} public override string GetDescription()
{
return beverage.GetDescription() + ", 摩卡";
}
}
}
namespace DecoratorPattern
{
/// <summary>
/// 奶泡装饰者
/// </summary>
public class Whip : Beverage
{
private Beverage beverage;
public Whip(Beverage b, float price)
{
beverage = b;
this.price = price;
}
public override float Cost()
{
return beverage.Cost() + price;
}
public override string GetDescription()
{
return (beverage.GetDescription() + " ,奶泡");
}
}
}
namespace DecoratorPattern
{
/// <summary>
/// 豆浆装饰者
/// </summary>
public class Soy : Beverage
{
private Beverage beverage;
public Soy(Beverage b, float price)
{
this.price = price;
beverage = b;
}
public override float Cost()
{
return beverage.Cost() + price;
} public override string GetDescription()
{
return( beverage.GetDescription() + ", 豆浆");
}
}
}
客户端类:CoffeeShop.cs
using System; namespace DecoratorPattern
{
class CoffeeShop
{
static void Main(string[] args)
{
//来一杯浓缩咖啡,不要调料
Beverage beverage = new Espresso(1.99f);
Console.WriteLine(beverage.GetDescription() + "$" + beverage.Cost()); //来一杯摩卡奶泡深焙咖啡
Beverage beverage2 = new DarkRoast(0.99f);
beverage2 = new Whip(beverage2, 0.1f); //用奶泡装饰深焙咖啡
beverage2 = new Mocha(beverage2, 0.2f); //再用摩卡装饰
Console.WriteLine(beverage2.GetDescription() + "$" + beverage2.Cost()); Console.ReadKey();
} }
}
运行结果:

参考资料《Head First 设计模式》
装饰者模式 Decorator的更多相关文章
- 浅谈设计模式--装饰者模式(Decorator Pattern)
挖了设计模式这个坑,得继续填上.继续设计模式之路.这次讨论的模式,是 装饰者模式(Decorator Pattern) 装饰者模式,有时也叫包装者(Wrapper),主要用于静态或动态地为一个特定的对 ...
- 【PHP设计模式 09_ZhuangShiQi.php】装饰器模式 (decorator)
<?php /** * [装饰器模式 (decorator)] * 有时候发布一篇文章需要经过很多人手,层层处理 */ header("Content-type: text/html; ...
- 设计模式(八)装饰器模式Decorator(结构型)
设计模式(八)装饰器模式Decorator(结构型) 1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法 ...
- 设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 用法
装饰者模式(Decorator Pattern) Java的IO类 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716 ...
- 设计模式 - 装饰者模式(Decorator Pattern) 具体解释
装饰者模式(Decorator Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者 ...
- 装饰器模式-Decorator(Java实现)
装饰器模式-Decorator(Java实现) 装饰器模式允许向一个现有的对象添加新的功能, 同时又不改变其结构. 其中 "现有对象"在本文中是StringDisplay类. 添加 ...
- 设计模式学习--装饰者模式(Decorator Pattern)
概念: 装饰者模式(Decorator Pattern): 动态地将功能添加到对象,相比生成子类更灵活,更富有弹性. 解决方案: 装饰者模式的重点是对象的类型,装饰者对象必须有着相同的接口,也也就是有 ...
- 大话设计模式--装饰者模式 Decorator -- C++实现实例
1.装饰者模式 Decorator 动态地给一个对象添加一个额外的职责, 就添加功能来说, 装饰模式比生成子类更为灵活. 每个装饰对象的实现和如何使用这个对象分离, 每个装饰对象只关心自己的功能,不 ...
- 设计模式(三):“花瓶+鲜花”中的装饰者模式(Decorator Pattern)
在前两篇博客中详细的介绍了"策略模式"和“观察者模式”,今天我们就通过花瓶与鲜花的例子来类比一下“装饰模式”(Decorator Pattern).在“装饰模式”中很好的提现了开放 ...
随机推荐
- Google代码规范
文件名 文件名须全部小写,下划线(_)和短横线(-) 源文件采用 UTF-8 编码. 非空代码块:K&R 风格 左花括号不另起新行 左花括号后紧跟换行 右花括号前需要换行 如果右花括号结束了语 ...
- Android应用程序MVC框架实例分析
问题提出:如何优雅地分离出应用程序的状态.用户交互和数据表现?如何通过框架体现工程的高性能.高灵活性.高响应性? MVC定义:model.view.controller三者的有机组合,分别表示:模型. ...
- Linux Supervisor的安装与使用入门
在linux或者unix操作系统中,守护进程(Daemon)是一种运行在后台的特殊进程,它独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件.由于在linux中,每个系统与用户进行交流的界 ...
- JS编码方式
1. escape(): 采用unicode字符集对指定的字符串除0-255以外进行编码.所有的空格符.标点符号.特殊字符以及更多有联系非ASCII字符都将被转化成%xx格式的字符编码(xx等于该字符 ...
- Array,prototype.concat.apply与[].conat.apply.
一直都知道JS数组Array内置对象有一个concat方法,但是也没怎么研究过,今天偶然就看了看 concat是连接一个或多个数组 返回的是连接后数组的一个副本 var oldArr=[]; var ...
- ORACLE PL/SQL编程:把触发器说透
本篇主要内容如下: 8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建触发器 8.2.1 触发器触发次序 8.2.2 创建DML触发器 8.2. ...
- swust oj 983
利用二叉树中序及后序遍历确定该二叉树的先序序列 1000(ms) 10000(kb) 2606 / 4908 已知二叉树的中序和先序遍历可以唯一确定后序遍历.已知中序和后序遍历可以唯一确定先序遍历,但 ...
- <c:forEach var="role" items="[entity.Role@d54d4d, entity.Role@1c61868, entity.Role@6c58db, entity.Role@13da8a5]"> list 集合数据转换异常
<c:forEach var="role" items="[entity.Role@d54d4d, entity.Role@1c61868, entity.Role ...
- linux --- Ansible篇
ansible背景 1.什么是ansible? ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优 ...
- 在linux服务器新添加硬盘,如何识别、挂载。
在linux服务器新添加硬盘,如何识别.怎样挂载磁盘.过程是怎么样. fdisk - manipulate disk partition tablemkfs - build a Linux files ...