设计模式--装饰者模式
装饰者模式:
动态的将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案.
解决问题:
在软件系统中,我们会需要通过继承来对类进行功能扩展,从而导致子类越来越多.
我们常喝的茶,茶中可以添加牛奶,可以添加糖.要求返回关于这个茶的描述以及价格.
刚开始通过继承来设计时,怎么设计呢?
设计4个类,Tea,MilkTea,SugarTea,SugarMilkTea
目前涉及添加的种类比较少,而且仅仅是针对茶,如果对茶进行分类:红茶,绿茶,同样可以添加Milk,可以添加Sugar,这是该怎么处理呢?
设计如下几个类:Tea,BlackTea,GreenTea,MilkBlackTea,MilkGreenTea,SugarBlackTea,SugarGreenTea,SugarMilkBlackTea,SugarMilkGreenTea
由此可以看出,再增加其他的物质,或者茶的种类再增加时,要设计类会更加多.而装饰者模式就可以解决这种类庞大的问题.
优点:
对于扩展功能.装饰者模式可以实现动态添加,在需要某种功能的时候,为其加上某种功能.当需要增加新的功能时,只需要添加新的装饰类,然后装饰对象即可.符合面向对象原则中的"优先使用组合而非继承"和"开放关闭原则".
缺点:
当装饰类有很多时,使用起来会很麻烦
结构图:
关于上面提出的茶、添加牛奶、添加糖的问题,采用装饰者模式设计出的类图如下:
有类图中,可以看出Milk继承自Decorator,Decorate继承自Tea,但是MilK和Tea又有什么关系呢?如果将Milk的类名改为MilkTea(添加了牛奶的茶)是否会更容易理解呢?同理,Sugar可以写为SugarTea(添加了糖的茶).此时,可能会和上面提出的几个类(Tea,BlackTea,GreenTea,MilkBlackTea,MilkGreenTea,SugarBlackTea,SugarGreenTea,SugarMilkBlackTea,SugarMilkGreenTea)有重复的地方.但是Milk和Sugar中有一个关于Tea的引用,此引用,大大的强化了对各种行为的组合.
代码:
关于Tea,BlackTea,GreenTea
public abstract class Tea2
{3
public Tea()4
{5
//6
//TODO: 在此处添加构造函数逻辑7
//8
}9

10
protected string description;11

12
public virtual string GetDescription()13
{14
return this.description;15
}16

17

18
public abstract int Cost();19
}20

21
public class BlackTeaOne :Tea22
{23
public BlackTeaOne()24
{25
this.description = "BlackTea";26
}27

28
public override int Cost()29
{30
return 10; 31
}32
}33

34
public class GreenTeaTwo :Tea35
{36
public GreenTeaTwo()37
{38
this.description = "GreenTea";39
}40

41
public override int Cost()42
{43
return 20;44
}45
}关于装饰者:
public abstract class Decorator : Tea2
{3
public Decorator()4
{5
//6
//TODO: 在此处添加构造函数逻辑7
//8
}9

10
public abstract override string GetDescription();11
}12

13
public class Milk : Decorator14
{15
Tea t;16

17
public Milk(Tea tea)18
{19
t = tea;20
}21

22
public override string GetDescription()23
{24
return t.GetDescription() + ",Milk";25
}26

27
public override int Cost()28
{29
return 1 + t.Cost();30
}31
}32

33
public class Sugar : Decorator34
{35
Tea t;36

37
public Sugar(Tea tea)38
{39
t = tea;40
}41

42
public override string GetDescription()43
{44
return t.GetDescription() + ",Sugar";45
}46

47
public override int Cost()48
{49
return 2 + t.Cost();50
}51
}页面调用:
protected void Page_Load(object sender, EventArgs e)2
{3
Tea t = new BlackTeaOne();4
Display(t);5

6
//添加牛奶7
t = new Milk(t);8
Display(t);9

10
//为添加了牛奶的茶添加糖11
t = new Sugar(t);12
Display(t);13
}14

15
void Display(Tea t)16
{17
Response.Write("名称:" + t.GetDescription() + "<br />价格:" + t.Cost() + "<hr/>");18
}页面显示:
名称:BlackTea2
价格:103
--------------------------------------------------------------------------------4
名称:BlackTea,Milk5
价格:116
--------------------------------------------------------------------------------7
名称:BlackTea,Milk,Sugar8
价格:139
--------------------------------------------------------------------------------适用性:
当一系列事物可以拥有相同的一系列的行为时,可以使用装饰者模式。
例如警察和土匪是被装饰者,他们的抽象就是人。拥有相同的行为指:可以装备刀,可以装备枪,可以装备手雷。但是,不是每一个警察或者土匪都必须装备刀,枪,手雷的。
此时,可以用装饰者模式,为一个单纯的人添加他的装备。
小结:
刚开始学习,自我总结,许多地方可能理解的不对,希望随着自己对设计模式的继续学习,可以有更大的进步。



浙公网安备 33010602011771号