你们还记得张江男、张江女两张图片吗?-装饰模式
一、前沿
张江男:指聚集在上海张江高科技园区,具备理工科背景,常常深居简出,工作勤奋,拙于表达。他们薪水很高,却不太会消费;他们有自己特有的浪漫,却难以招女孩喜欢;他们智商很高,却普遍想法简单。 他们被武断地概念化为“张江男”。 专家说,他们是一群不懂生活的“废弃生命”;老人们说,他们是可靠的结婚对象;女孩们说,他们更喜欢看电脑而不是看我;而这群被冠以“张江难”的年轻人却说:我们并不寂寞,也很浪漫。
张江女,现于张江某IT公司工作,工作时一头长发无时间打理,黑框眼镜下是长时间对着电脑而导致的近视眼,右手手机左手杂粮煎饼,深色的大衣和干练的牛仔再配上白色的舒适平底鞋,神魂好似已经云游天际之外,这俨然就是现在的张江女们上班标准匹配。
不要嘲笑他们,他们是程序员,他们为工作在默默的付出,他们心酸的背后有丰厚的回报。
张江男一般26岁就月薪税后1w,30岁就至少2w+了,牛逼的35岁的时候基本年薪50万或者100万了,他们就是这么吊的一群人。
其实张江男、张江女的形象就是我们大众程序的写照,但是我们有他们的标配打扮,没有他们客观的收入,这是我们在读的程序员值得反思的地方。
说了这么多也该回归点正题了,今天我们就说说设计模式中的装饰模式。
二、基本概念
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。
装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。
装饰模式包括四个角色:
抽象构件角色(Component):定义一个抽象接口,用以给这些对象动态地添加职责。
具体构件角色(ConcreteComponent):定义一个具体的对象,也可以给这个对象添加一些职责。
装饰类角色(Decorator): 装饰抽象类,继承了Component,从外类来扩展Component类的功能。
具体装饰者角色(ConcretorDecorator):负责给构建对象添加职责。
三、代码分析
根据四个角色做出具体代码:
// 抽象构件 public abstract class Component { public abstract void Opration(); } // 具体构件 public class ConcreteComponent : Component { public override void Opration() { Console.WriteLine("具体构件的基本操作"); } } /// <summary> /// 抽象的装饰类,它不能初始化对象。 /// </summary> public abstract class Decorator : Component { protected Component Component; public void SetComponent(Component component) { this.Component = component; } /// <summary> /// 重写Operation,实际执行的是Component的Operation。 /// </summary> public override void Opration() { if (Component != null) { Component.Opration(); } } } //具体装饰类A public class ConcreteDecoratorA : Decorator { private void SpecialOpration() { Console.WriteLine("A的操作"); } public override void Opration() { base.Opration(); this.SpecialOpration(); } } //具体装饰类B public class ConcreteDecoratorB : Decorator { private void SpecialOprationA() { Console.WriteLine("B的A操作"); } private void SpecialOprationB() { Console.WriteLine("B的B操作"); } public override void Opration() { base.Opration(); this.SpecialOprationA(); this.SpecialOprationB(); } } static void Main(string[] args) { //定义构件 ConcreteComponent concreteComponent = new ConcreteComponent(); //定义具体装饰类 ConcreteDecoratorA a = new ConcreteDecoratorA(); ConcreteDecoratorB b = new ConcreteDecoratorB(); //把AB的操作交给构件 a.SetComponent(concreteComponent); b.SetComponent(a); //构件除了自己的基本操作,还具有A的操作、B的操作,最终执行b.Opration(); b.Opration(); Console.ReadKey(); }
运行结果:
很容易理解,就是增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。
四、实例分析
开头说了那么多张江男和张江女的事情,我们就依照这个实例写个代码:
//抽象人 public abstract class Person { public abstract void Show(); } //张江男 public class ZhangJiangItMan : Person { public override void Show() { Console.WriteLine("只穿了基本必要装扮!"); } } //张江女 public class ZhangJiangItWoMan : Person { public override void Show() { Console.WriteLine("只穿了基本必要装扮!"); } } //穿着打扮 public abstract class Dress : Person { protected Person Person; //开始装扮 public void SetDress(Person person) { this.Person = person; } public override void Show() { if (Person != null) { Person.Show(); } } } //具体服装打扮 public class Backpack : Dress { public override void Show() { base.Show(); Console.WriteLine("张江男必备双肩包!"); } } //眼镜 public class Glasses : Dress { public override void Show() { base.Show(); Console.WriteLine("张江男张江女必备黑框眼镜!"); } } //万能搭配的衬衫 public class Shirt : Dress { public override void Show() { base.Show(); Console.WriteLine("张江男张江女必备万能搭配的衬衫!"); } } //万能搭配的牛仔裤 public class Jeans : Dress { public override void Show() { base.Show(); Console.WriteLine("张江男张江女必备万能搭配的牛仔裤!"); } } static void Main(string[] args) { //实例化服饰 Backpack backpack = new Backpack(); Glasses glasses = new Glasses(); Shirt shirt = new Shirt(); Jeans jeans = new Jeans(); //实例化张江男 ZhangJiangItMan zhangJiangItMan = new ZhangJiangItMan(); //开始装扮 backpack.SetDress(zhangJiangItMan); glasses.SetDress(backpack); shirt.SetDress(glasses); jeans.SetDress(shirt); //输出张江男装扮 jeans.Show(); //实例化张江女 ZhangJiangItWoMan zhangJiangItWoMan = new ZhangJiangItWoMan(); backpack.SetDress(zhangJiangItWoMan); glasses.SetDress(backpack); shirt.SetDress(glasses); jeans.SetDress(shirt); //输出张江女装扮 jeans.Show(); Console.ReadKey(); }
运行结果:
就这么简单,就这么好理解
五、总结
优点:
装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
缺点:
这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
代码下载:https://yunpan.cn/cYpIGJCDwNqce (提取码:9e33)