装饰者模式:是对继承的另一种体现,在子类很少的情况下使用继承是是比较方便的,但是随着子类越来越多,装饰者模式就能体现出好处了。
定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
目的:减少子类多的情况,能动态的搭配需要添加的东西。
一般的继承就是线性思维,需要什么就在上面写啥。
装饰者模式就是将利用(依赖倒置这点)将实现一个装饰盒子插口(实现抽象的装饰本文对应 HandCatchCakeDecorate),之后实现的插件模块(对应AddEggHandCatchCake和AddMeatFlossHandCatchCake)可以拔插式的安装或者去除。
这里不过多叙述为甚么需要装饰者模式,网上有很多生动的例子:如 https://www.cnblogs.com/of-fanruice/p/11565679.html,https://www.jianshu.com/p/4a530a3c70af
上面两个其中有人拿煎饼果子举例,这里我个人喜欢手抓饼,我就以手抓饼来举例子;这里直接上代码如何实现装饰者模式
1.首先定义一个抽象的手抓饼类
public abstract class AbstractHandCatchCake { public abstract string Print(); }
2.实现手抓饼类
public class HandCatchCake:AbstractHandCatchCake { public override string Print() { return "手抓饼"; } }
实现完成后如果想在手抓饼里假如其他作料可以1.重新继承AbstractHandCatchCake,在对print();方法重写假如自己的方法。2.可以继承现有的HandCatchCake,在他的基础上重写。但是这种方式都是要在调用前写好,而且种类多就不和合适了,因为种类多,子类就多。
因此装饰者模式就出现了解决这尴尬显现。
在写装饰者代码前,先了解下①谁又被装饰了,②装饰者是谁,③该如何装饰:
①.被装饰的是HandCatchCake,要在他上面添加需要的作料。
②.在定义咋装饰者前,需要先(AbstractHandCatchCake)的一个扩展类,将这个抽象扩展成可以添加装饰类。
这里定义的类继承了抽象方法,定义成员变量,定义构造函数都是该抽象,目的是为了后面加装饰用;方法调用抽象的print();
这里的操作就像是制作一个盒子模型,将需要的装饰的放上去。
这里需要注意他的定义都是使用抽象的,(依赖倒置)才能进行装饰。
public class HandCatchCakeDecorate:AbstractHandCatchCake { private AbstractHandCatchCake handCatchCake; public HandCatchCakeDecorate(AbstractHandCatchCake handCatchCake) { this.handCatchCake = handCatchCake; } public override string Print() { return handCatchCake.Print(); } }
装饰者是主动去装饰那个人,这里我使用了两个装饰者一个添加蛋,一个添加肉松.
class AddEggHandCatchCake:HandCatchCakeDecorate { public AddEggHandCatchCake(AbstractHandCatchCake handCatchCake) : base(handCatchCake) { } public override string Print() { return base.Print()+ AddEgg(); } public string AddEgg() { return "添加一个蛋"; } }
class AddMeatFlossHandCatchCake: HandCatchCakeDecorate { public AddMeatFlossHandCatchCake(AbstractHandCatchCake handCatchCake) : base(handCatchCake) { } public override string Print() { return base.Print()+ AddMeatFloss(); } public string AddMeatFloss() { return "添加一份肉松"; } }
他们都继承那个被装饰的HandCatchCakeDecorate,并且都有自己的print方法,加蛋方法里是base.Print()+ AddEgg();就是在原基础上加了个蛋;加肉松也是一样的。
③该如何装饰
上面的被装饰是HandCatchCake(手抓饼实例)我们就需要在(手抓饼)上面添加蛋和肉松或其他想要的,就像堆叠在上面一样。
调用方式;
static void Main(string[] args) { AbstractHandCatchCake hcc = new HandCatchCake(); hcc.Print(); //动态添加装饰者 //加了两个蛋 AbstractHandCatchCake hccAddEgg1 = new AddEggHandCatchCake(hcc); AbstractHandCatchCake hccAddEgg2 = new AddEggHandCatchCake(hccAddEgg1); //加了份肉松 AddMeatFlossHandCatchCake hccAddMeatFloss = new AddMeatFlossHandCatchCake(hccAddEgg2); string s= hccAddMeatFloss.Print();
Console.OutputEncoding = System.Text.Encoding.UTF8; Console.WriteLine(s); Console.ReadLine(); }
结果
最后总结下
好处:1.在不改变对象情况下能加入新的,运行时才添加新的。
2.更加自由,能自由的搭配选择,自己更加简单的选择装饰内容。
缺点:1.需要写更多的代码
2.如果过多的装饰在调试时会增加很多工作量。
使用范围:对灵活,多组和的场景特别适用,在C#里BufferedStream就属于装饰者模式的体现。