装饰者模式 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).在“装饰模式”中很好的提现了开放 ...
随机推荐
- 17使用systemd方式开机自动启动Home Assistant服务
2018-03-20 15:48:36 转移自网易博客! 首先使用编写文件hass@homeassistant.service,文件内容如下 # 这个文件用于systemd方式自动启动hass服务.# ...
- centos7.4中安装docker
#!/bin/sh # 安装docker # 在docker中安装mysql # 解决了docker容器中无法输入中文的问题 ##########################安装docker # ...
- centos中安装基础环境
进入到相关目录cd /usr/bin安装python3yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-dev ...
- 如何根据checkbox的值进行勾选!例:我要勾选value等于scanbuy,terminal的复选框!
微商城 随手购 自助购 <div class="controls" id="client"> <input id="mall&quo ...
- [LeetCode] Convert Binary Search Tree to Sorted Doubly Linked List 将二叉搜索树转为有序双向链表
Convert a BST to a sorted circular doubly-linked list in-place. Think of the left and right pointers ...
- JS-对象的数据重复
<title>01-对象中数据的重复</title> <script type="text/javascript"> var arr = []; ...
- 书上关于*(p++)表达式的几种变形形式的思考题
代码: int main(){ int a[10] = { 1,2,3,4,5,6,7,8,9,10 }; int *p = &a[3]; cout << "*p++ = ...
- android 自定义Button,抛弃写shape文件
标签: android 控件 自定义 2017年05月27日 17:52:13 611人阅读 评论(0) 收藏 举报 分类: 自定义View(2) 作者同类文章 X 版权声明:本文为博主原创文章 ...
- react-native-Cocoapods-Swift-Project
https://reactnative.cn/docs/integration-with-existing-apps/ 1.创建一个xcode工程,single View就行,项目语言选择swift, ...
- Mock Server 实现post方法的接口(三)
Mock Server 实现post方法的接口(三) 1.mock server实现的接口,当request中未设置"method"时,会自动将所有method试一次,所以一定要指 ...