步步为营 .NET 设计模式学习笔记 十四、Decorator(装饰模式)
概述
在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?这就是本文要讲的Decorator模式。
一个场景是我们要为一个对象动态添加新的职责,这个职责并不修改原有的行为,而是在原有行为基础上添加新的功能,就好比装饰工人为一座新居的墙上涂抹上色彩缤纷的颜料一般。
意图
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。[GOF 《设计模式》]
<Design Pattern>结构图
图1 Decorator模式结构图
在装饰模式中的各个角色有:
- 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
- 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
- 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
- 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。
生活中的例子
装饰模式动态地给一个对象添加额外的职责。不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。
图2 使用有画框的画作为例子的装饰模式对象图
示例用例图
在超市里,平常节日都有优惠活动,不同节日有不同优惠活动,我们用装饰模式写一个超市节日打折的例子,用例图如下:
代码设计
先创建SuperMarket.cs:
public abstract class SuperMarket { private int _CategoryNumber; public int CategoryNumber { get { return _CategoryNumber; } set { _CategoryNumber = value; } } private string _Name; public string Name { get { return _Name; } set { _Name = value; } } private double _Discount; public double Discount { get { return _Discount; } set { _Discount = value; } } private string _Festival; public string Festival { get { return _Festival; } set { _Festival = value; } } public abstract string ShowInfo(); }
再创建Decorator.cs:
public abstract class Decorator : SuperMarket { protected SuperMarket superMarker; public Decorator(SuperMarket superMarker) { this.superMarker = superMarker; } public override string ShowInfo() { return superMarker.ShowInfo(); } }
再创建WalMart .cs:
public class WalMart:SuperMarket { public WalMart() { this.CategoryNumber = 1000; this.Discount = 0.95; this.Name = "沃尔玛"; this.Festival = "平常"; } public override string ShowInfo() { StringBuilder strBuilder = new StringBuilder(); strBuilder.AppendFormat("在{0}超市,{1}节日期间,折扣为{2}的商品种类有{3}类
. ", this.Name,this.Festival, this.Discount, this.CategoryNumber); return strBuilder.ToString(); } }
再创建MidAutumnFestival.cs:
public class MidAutumnFestival : Decorator { public MidAutumnFestival(SuperMarket superMarket) : base(superMarket) { } public void Preferential() { superMarker.Discount = 0.95; superMarker.CategoryNumber = 1500; superMarker.Festival = "中秋节"; } public string MoonCake() { return "期间所有月饼8折优惠"; } }
再创建SpringFestival.cs:
public class SpringFestival : Decorator { public SpringFestival(SuperMarket supermarket) : base(supermarket) { } public void Preferential() { superMarker.Discount = 0.9; superMarker.CategoryNumber = 2100; superMarker.Festival = "春节"; } public string GiftPreferential() { return "期间有100种礼品类商品8折优惠."; } }
最后再调用:
public partial class Run : Form { public Run() { InitializeComponent(); } private void btnRun_Click(object sender, EventArgs e) { //------------------------------------- SuperMarket superMarket = new WalMart(); rtbResult.AppendText(superMarket.ShowInfo()+" "); SpringFestival springFestival = new SpringFestival(superMarket); springFestival.Preferential(); rtbResult.AppendText(springFestival.ShowInfo()); rtbResult.AppendText(springFestival.GiftPreferential()+" "); MidAutumnFestival midAutumnFestival = new MidAutumnFestival(superMarket); midAutumnFestival.Preferential(); rtbResult.AppendText(midAutumnFestival.ShowInfo()); rtbResult.AppendText(midAutumnFestival.MoonCake() + " "); } }
结果如下图:
补充:Web开发 , ASP.Net ,