设计模式--装饰者模式

时间:2022-09-09 09:11:15

装饰者模式:

动态的将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案.

解决问题:

在软件系统中,我们会需要通过继承来对类进行功能扩展,从而导致子类越来越多.

我们常喝的茶,茶中可以添加牛奶,可以添加糖.要求返回关于这个茶的描述以及价格.

刚开始通过继承来设计时,怎么设计呢?

设计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

 1 设计模式--装饰者模式public   abstract   class  Tea
 2 设计模式--装饰者模式设计模式--装饰者模式 {
 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 :Tea
22 设计模式--装饰者模式设计模式--装饰者模式 {
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 :Tea
35 设计模式--装饰者模式设计模式--装饰者模式 {
36设计模式--装饰者模式    public GreenTeaTwo()
37设计模式--装饰者模式设计模式--装饰者模式    {
38设计模式--装饰者模式        this.description = "GreenTea";
39设计模式--装饰者模式    }

40设计模式--装饰者模式
41设计模式--装饰者模式    public override int Cost()
42设计模式--装饰者模式设计模式--装饰者模式    {
43设计模式--装饰者模式        return 20;
44设计模式--装饰者模式    }

45设计模式--装饰者模式}

关于装饰者:

 1 设计模式--装饰者模式public   abstract   class  Decorator : Tea
 2 设计模式--装饰者模式设计模式--装饰者模式 {
 3设计模式--装饰者模式    public Decorator()
 4设计模式--装饰者模式设计模式--装饰者模式    {
 5设计模式--装饰者模式        //
 6设计模式--装饰者模式        //TODO: 在此处添加构造函数逻辑
 7设计模式--装饰者模式        //
 8设计模式--装饰者模式    }

 9设计模式--装饰者模式
10设计模式--装饰者模式    public abstract override string GetDescription();
11设计模式--装饰者模式}

12 设计模式--装饰者模式
13 设计模式--装饰者模式 public   class  Milk : Decorator
14 设计模式--装饰者模式设计模式--装饰者模式 {
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 : Decorator
34 设计模式--装饰者模式设计模式--装饰者模式 {
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设计模式--装饰者模式}
页面调用:
 1 设计模式--装饰者模式     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设计模式--装饰者模式    }
页面显示:
1 设计模式--装饰者模式名称:BlackTea
2 设计模式--装饰者模式价格: 10
3 设计模式--装饰者模式 --------------------------------------------------------------------------------
4 设计模式--装饰者模式名称:BlackTea,Milk
5 设计模式--装饰者模式价格: 11
6 设计模式--装饰者模式 --------------------------------------------------------------------------------
7 设计模式--装饰者模式名称:BlackTea,Milk,Sugar
8 设计模式--装饰者模式价格: 13
9 设计模式--装饰者模式 --------------------------------------------------------------------------------





适用性:
当一系列事物可以拥有相同的一系列的行为时,可以使用装饰者模式。
例如警察和土匪是被装饰者,他们的抽象就是人。拥有相同的行为指:可以装备刀,可以装备枪,可以装备手雷。但是,不是每一个警察或者土匪都必须装备刀,枪,手雷的。
此时,可以用装饰者模式,为一个单纯的人添加他的装备。
 
小结:
刚开始学习,自我总结,许多地方可能理解的不对,希望随着自己对设计模式的继续学习,可以有更大的进步。