装饰模式(Decorator)——动态的给一个对象添加一些额外的职责,就增加功能而言,装饰模式比生产子类更加灵活。
在日常开发中,经常会遇见一个对象有很多的功能,但是这些功能有时候是需要的,有的时候并不需要其他功能,只用到了这个对象中的一部分功能。这样,类的复杂度就比较高,违背了单一责任原则和开发-封闭原则。这时候就需要装饰模式。
装饰模式是为已有功能动态的添加更多功能的一种方式。当系统需要新功能时,是向旧的类中添加的代码通常作用就是给原有的类的核心职责添加一些行为。当使用装饰模式的时候,保持原有的类的核心责任不变,动态的给增加功能。这样,当执行特殊行为的时候,客户端代码就可以在运行中有选择的,按顺序的给核心功能进行装饰,实现特殊需求。
1.Component类,这个一个抽象类,定义了对象的核心抽象方法。
1 /// <summary> 2 /// 抽象类,定义了一个功能 3 /// </summary> 4 abstract class Component 5 { 6 /// <summary> 7 /// 核心功能的抽象方法 8 /// </summary> 9 public abstract void Show(); 10 }
2.ConcreteComponent类,这里类定义了具体的对象,对象重写了抽象类的核心抽象方法,使自己有了核心的功能。
1 /// <summary> 2 /// 具体的被装饰的对象 3 /// </summary> 4 class Person:Component 5 { 6 public Person(){} 7 8 private string name; 9 /// <summary> 10 /// 对象可以有自己的属性等功能 11 /// </summary> 12 /// <param name="name"></param> 13 public Person(string name) 14 { 15 this.name = name; 16 } 17 18 /// <summary> 19 /// 重写抽象方法,有了自己的核心功能 20 /// </summary> 21 public override void Show() 22 { 23 Console.WriteLine("装扮的{0}",name); 24 } 25 }
3.Decorator类,装饰类,负责对对象的装饰,不仅是对原始核心对象进行装饰,同时也对已经装饰过的对象进行再次装饰。
1 /// <summary> 2 /// 给对象进行包装 3 /// </summary> 4 abstract class Finery:Person 5 { 6 protected Person person; 7 8 /// <summary> 9 /// 给对象进行具体的包装 10 /// </summary> 11 /// <param name="person"></param> 12 public void Decorate(Person person) 13 { 14 this.person = person; 15 } 16 17 /// <summary> 18 /// 让给包装过的对象可以重新展示。 19 /// </summary> 20 public override void Show() 21 { 22 if (person != null) 23 { 24 person.Show(); 25 } 26 } 27 }
4.ConcreteDecorator类,给对象进行具体装饰的类,有多个,相互独立,想进行哪种装饰就用哪个类进行装饰,也可以进行不同顺序的装饰。
1 /// <summary> 2 /// 具体包装的产品 3 /// </summary> 4 class TShirts:Finery 5 { 6 //这里可以执行操作,进行包装 7 8 public override void Show() 9 { 10 Console.Write("大T恤"); 11 base.Show(); 12 } 13 } 14 15 /// <summary> 16 /// 具体包装的产品 17 /// </summary> 18 class BigTrouser:Finery 19 { 20 //这里可以执行操作,进行包装 21 22 public override void Show() 23 { 24 Console.Write("垮裤"); 25 base.Show(); 26 } 27 } 28 29 /// <summary> 30 /// 具体包装的产品 31 /// </summary> 32 internal class Sneakers : Finery 33 { 34 //这里可以执行操作,进行包装 35 36 public override void Show() 37 { 38 Console.Write("破球鞋"); 39 base.Show(); 40 } 41 }
5.客户端代码,产品给装饰完成,该展示了,现在我们有核心对象,有各种装饰方法,可以自由的选择怎么去装饰,然后展示。
1 static void Main(string[] args) 2 { 3 //创建被装饰的对象 4 var person=new Person("小明"); 5 //创建装饰的对象 6 var sneakers=new Sneakers(); 7 var bigTrouser=new BigTrouser(); 8 var tShirts=new TShirts(); 9 10 //对对象进行第一次装饰 11 sneakers.Decorate(person); 12 //对对象进行第二次装饰 13 bigTrouser.Decorate(sneakers); 14 //对对象进行第三次装饰 15 tShirts.Decorate(bigTrouser); 16 //装饰完成,展示。 17 tShirts.Show(); 18 Console.ReadKey(); 19 }
装饰模式的优点就是把类中的装饰功能从类中搬移出去,这样可以简化原有的类,有效的把类的核心职责和装饰功能区分开了。这样可以去除相关类中重复的装饰逻辑。
在日常开发中,什么时候可以用到装饰模式呢,比如对数据的处理,现在一个类产出了一些数据,我们需要对这些数据进行处理,也就是进行装饰,现在有加密、过滤、格式化三种装饰,有的时候仅需加密,有的时候同时需要加密和过滤。
同时装饰中处理顺序也不同,比如同时需要对数据进行这三种处理,这时候需要有序的对数据进行装饰,先过滤,然后格式化,最近加密,一目了然。
以上内容部分参考程杰的《大话设计模式》一书