设计模式:装饰模式(decorate)
还是那几句话:
学无止境,精益求精
十年河东,十年河西,莫欺少年穷
学历代表你的过去,能力代表你的现在,学习代表你的将来
废话不多说,直接进入正题:
今天学习了装饰模式,但是代码看不太懂,于是我将装饰模式的代码改编成了如下代码:
如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SJMS { public abstract class Component { public abstract void Operation(); } public abstract class Deaorator : Component { public void SetComponent(Component component) { component.Operation(); } } public class ConcreteDeaoratorC : Deaorator { public override void Operation() { Console.WriteLine("具体装饰对象C的操作"); } } public class ConcreteDeaoratorA : Deaorator { private string addedState; public override void Operation() { addedState = "New State"; Console.WriteLine("具体装饰对象A的操作"); } } public class ConcreteDeaoratorB : Deaorator { public override void Operation() { AddedBehavior(); Console.WriteLine("具体装饰对象B的操作"); } private void AddedBehavior() { } } }
客户端代码如下:
static void Main(string[] args) { ConcreteDeaoratorA a = new ConcreteDeaoratorA(); ConcreteDeaoratorB b = new ConcreteDeaoratorB(); ConcreteDeaoratorC c = new ConcreteDeaoratorC(); // a.SetComponent(a); b.SetComponent(b); c.SetComponent(c); // Console.ReadKey(); }
针对上述的代码,自己又思索了一番,猛然间想到了设计模式:策略模式,再看看上述的代码,感觉是策略模式的升级版,呵呵。
我之前写的策略模式博客原文如下:商场促销-策略模式(和简单工厂模式很像的哇) C#
大家对比下,是不是比之前的策略模式还要简单?
OK,言归正传,之所有有上述的理解,说明我对装饰模式还是不太理解!
现在把装饰模式的代码贴出来,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SJMS { public abstract class Component { public abstract void Operation(); } public class ConcreteComponent : Component { public override void Operation() { Console.WriteLine("具体对象操作"); } } public abstract class Deaorator : Component { protected Component component; public void SetComponent(Component component) { this.component = component; } public override void Operation() { if (component != null) { component.Operation(); } } } public class ConcreteDeaoratorA : Deaorator { private string addedState; public override void Operation() { base.Operation(); addedState = "New State"; Console.WriteLine("具体装饰对象A的操作"); } } public class ConcreteDeaoratorB : Deaorator { public override void Operation() { base.Operation(); AddedBehavior(); Console.WriteLine("具体装饰对象B的操作"); } private void AddedBehavior() { } } }
客户端调用如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SJMS { class Program { static void Main(string[] args) { ConcreteComponent c = new ConcreteComponent(); ConcreteDeaoratorA d1 = new ConcreteDeaoratorA(); ConcreteDeaoratorB d2 = new ConcreteDeaoratorB(); // d1.SetComponent(c); d2.SetComponent(d1); d2.Operation(); // Console.ReadKey(); } } }
现在贴出上述代码的UML类图:
大话设计模式中程杰老师给出的定义,装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活。
可以看出:
装饰模式是利用SetComponent 来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离了,每个装饰对象值关心自己功能,不需要关心如何被添加到对象链当中。
装饰模式,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类的中重复的装饰逻辑。
亦可以看出:
各个子类都有自己独特的特性,比如:ConcreteDeaoratorA 类拥有私有属性:addedState ,ConcreteDeaoratorB 类用于自己的行为:AddedBehavior() 函数。总之,子类继承了父类,但同时也扩展了父类没有的行为属性。
因此我们得出如下结论(装饰模式的应用场景):
当系统需要新功能的时候,是向旧类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为。通常需要在父类中加入新的字段,新的方法和新的逻辑,从而增加了主类的复杂度。而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。
于是,为了这种特定的、特殊的、特有的属性/行为,装饰模式呼之欲出......
而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。
装饰模式的优点:把类中装饰功能从类中搬移去除,这样可以简化原有的类;有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。
注意:装饰器的顺序至关重要
今天,我们结合具体的例子来说明(大话设计模式采用的例子是菜鸟见美眉,不同的衣服搭配来讲解装饰模式的):
代码如下:
/// <summary> /// 人类 /// </summary> public abstract class Person { public abstract void Operation(); } public class Deaorator : Person { public string Name; public Deaorator() { } public Deaorator(string name) { this.Name = name; } protected Person person; public void SetComponent(Person _person) { this.person = _person; } public override void Operation() { if (person != null) { person.Operation(); } } } public class 大体恤 : Deaorator { public override void Operation() { Console.WriteLine("大体恤"); base.Operation(); } } public class 破球鞋 : Deaorator { public override void Operation() { Console.WriteLine("破球鞋"); base.Operation(); } } public class 大裤衩 : Deaorator { public override void Operation() { Console.WriteLine("大裤衩"); base.Operation(); } } public class 小裤头 : Deaorator { public override void Operation() { Console.WriteLine("小裤头"); base.Operation(); } }
调用代码如下:
namespace SJMS { class Program { static void Main(string[] args) { Deaorator d = new Deaorator("陈卧龙"); Console.WriteLine("陈卧龙的装扮如下:"); 大体恤 c = new 大体恤(); 破球鞋 d1 = new 破球鞋(); 大裤衩 d2 = new 大裤衩(); 小裤头 d3 = new 小裤头(); // d1.SetComponent(c); d2.SetComponent(d1); d3.SetComponent(d2); d3.Operation(); // Console.ReadKey(); } } }
输出如下:
OK,先穿小裤头,再依次穿大裤衩、破球鞋,大体恤。这个穿戴顺序还可以哈!
将代码修改如下:
class Program { static void Main(string[] args) { Deaorator d = new Deaorator("陈卧龙"); Console.WriteLine("陈卧龙的装扮如下:"); 大体恤 c = new 大体恤(); 破球鞋 d1 = new 破球鞋(); 大裤衩 d2 = new 大裤衩(); 小裤头 d3 = new 小裤头(); // d1.SetComponent(c); d3.SetComponent(d1); d2.SetComponent(d3); d2.Operation(); // Console.ReadKey(); } }
这样陈卧龙的小裤头就穿在外边了!呵呵,似乎有点不妥!因此,装饰的顺序很重要!
另外,整个装饰过程是一次性完成的,关键代码体现在: base.Operation();
@陈卧龙的博客