装饰者模式 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).在“装饰模式”中很好的提现了开放 ...
随机推荐
- Django实例
更新:今年8月在深圳和嵩天老师居然见面了,很开心.嵩天老师很和蔼. =========== 今天看了嵩天老师的视频,感觉讲的很好,于是看着视频自己做了一个初步的实例认识. 步骤1,新建一个Web框架 ...
- Fiddler 教程---小坦克
协议. Fiddler无论对开发人员或者测试人员来说,都是非常有用的工具 Fiddler的工作原理 Fiddler 是以代理web服务器的形式工作的,它使用代理地址:127.0.0.1, 端口:888 ...
- [LeetCode] Short Encoding of Words 单词集的短编码
Given a list of words, we may encode it by writing a reference string S and a list of indexes A. For ...
- jquery运用FormData结合Ajax异步上传表单,超实用
首先创建一个formData,其中参数,就是你的form表单,jquery要加0,也可以用document.querySelector("form")得到 var formData ...
- python自动化打开网页
from selenium.webdriver.firefox.options import Options as FOptionsfrom selenium.webdriver.chrome.opt ...
- 秒杀ecshop的前台写shell 0day
ECSHOP号称最大的开源网店系统,官方是这样介绍它的:“ECShop网店系统是一套免费开源的网上商店软件,无论在稳定性.代码优化.运行效率.负载能力.安全等级.功能可操控性和权限严密性等方面都居国内 ...
- 火狐浏览器安装firebug和firepath插件方法(离线)
1.下载FF55以内版本安装包,安装后在Firefox 更新选择"不检查更新" 2.火狐浏览器各个版本下载地址:http://ftp.mozilla.org/pub/firefox ...
- shell 爬取图片下载到本地
#!/bin/bash #ddmm // #if [ -z $string ] 如果string 为空 #-z STRING the length of STRING is zero read -p ...
- STA 463 Simple Linear Regression Report
STA 463 Simple Linear Regression ReportSpring 2019 The goal of this part of the project is to perfor ...
- Centos 安装Java jdk
1/ yum search java|grep jdk 2/ yum install java-......... 3/ vi /etc/profile 在最后添上: 4/ source /etc/p ...