设计模式-结构型-装饰者模式
装饰者模式(wrapper):
允许向一个现有的对象添加新的功能,同时又不改变其结构。装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
示例:英雄学习技能
1 public class Program 2 { 3 private static void Main(string[] args) 4 { 5 //选择英雄 6 Hero hero = new BlindMonk(); 7 Skills skills = new Skills(hero); 8 Skills r = new Skill_R(skills, "猛龙摆尾"); 9 Skills e = new Skill_E(r, "天雷破/摧筋断骨"); 10 Skills w = new Skill_W(e, "金钟罩/铁布衫"); 11 Skills q = new Skill_Q(w, "天音波/回音击"); 12 //学习技能 13 q.learnSkill(); 14 } 15 } 16 17 /// <summary> 18 /// Component 英雄接口 19 /// </summary> 20 public interface Hero 21 { 22 void learnSkill(); 23 } 24 25 /// <summary> 26 /// ConcreteComponent 具体英雄盲僧 27 /// </summary> 28 public class BlindMonk : Hero 29 { 30 public void learnSkill() 31 { 32 Console.WriteLine($"盲僧学习了以上技能!"); 33 } 34 } 35 36 /// <summary> 37 /// Decorator 技能栏 38 /// </summary> 39 public class Skills : Hero 40 { 41 private Hero hero; 42 43 public Skills(Hero hero) 44 { 45 this.hero = hero; 46 } 47 48 public virtual void learnSkill() 49 { 50 if (hero != null) 51 hero.learnSkill(); 52 } 53 } 54 55 /// <summary> 56 /// ConreteDecorator 技能:Q 57 /// </summary> 58 public class Skill_Q : Skills 59 { 60 private string _skillName; 61 62 public Skill_Q(Hero hero, string skillName) : base(hero) 63 { 64 this._skillName = skillName; 65 } 66 67 public override void learnSkill() 68 { 69 Console.WriteLine($"学习了技能Q:{this._skillName}"); 70 base.learnSkill(); 71 } 72 } 73 74 /// <summary> 75 /// ConreteDecorator 技能:W 76 /// </summary> 77 public class Skill_W : Skills 78 { 79 private string _skillName; 80 81 public Skill_W(Hero hero, string skillName) : base(hero) 82 { 83 this._skillName = skillName; 84 } 85 86 public override void learnSkill() 87 { 88 Console.WriteLine($"学习了技能W:{this._skillName}"); 89 base.learnSkill(); 90 } 91 } 92 93 /// <summary> 94 /// ConreteDecorator 技能:E 95 /// </summary> 96 public class Skill_E : Skills 97 { 98 private string _skillName; 99 100 public Skill_E(Hero hero, string skillName) : base(hero) 101 { 102 this._skillName = skillName; 103 } 104 105 public override void learnSkill() 106 { 107 Console.WriteLine($"学习了技能E:{this._skillName}"); 108 base.learnSkill(); 109 } 110 } 111 112 /// <summary> 113 /// ConreteDecorator 技能:R 114 /// </summary> 115 public class Skill_R : Skills 116 { 117 private string _skillName; 118 119 public Skill_R(Hero hero, string skillName) : base(hero) 120 { 121 this._skillName = skillName; 122 } 123 124 public override void learnSkill() 125 { 126 Console.WriteLine($"学习了技能R:{this._skillName}"); 127 base.learnSkill(); 128 } 129 }
装饰者模式有四个角色:
1)抽象构建(Component ):给出一个抽象接口,来规范被添加职责的对象;
2)具体构件(ConcreteComponent):定义一个将要接收附加责任的具体对象;
3)装饰抽象类(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口;
4)具体装饰对象(ConreteDecorator):负责给构件对象 ”贴上“附加的责任。起到给Component添加职责的功能。
要点:
1)装饰者和被装饰对象有相同的超类型。
2)可以用一个或多个装饰者包装一个对象。
3)装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。
4)对象可以在任何时候被装饰,所以可以在运行时动态的,不限量的用你喜欢的装饰者来装饰对象。
5)装饰模式中使用继承的关键是想达到装饰者和被装饰对象的类型匹配,而不是获得其行为。
6)装饰者一般对组件的客户是透明的,除非客户程序依赖于组件的具体类型。在实际项目中可以根据需要为装饰者添加新的行为,做到“半透明”装饰者。
.NET中装饰者的使用:
MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99}); // 扩展缓冲的功能 BufferedStream buffStream = new BufferedStream(memoryStream); // 添加加密的功能 CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write); // 添加压缩功能 GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);
装饰者模式的优缺点:
优点:1)装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活;
2)通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合;
3)装饰者模式有很好地可扩展性
缺点:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。
装饰者模式与代理模式的区别:
1)两种模式的关注点不同,装饰者模式关注的是在一个对象上动态的添加方法,而代理模式关注的是控制对象的访问。
2)装饰者模式可以让使用者直观的看到增强了哪些功能,而代理模式完全限制了使用者,只去调用代理,至于代理里面增加了什么功能,使用者是不知道,隐藏了一个对象的具体信息,这正是为什么代理模式在初始化时不能像装饰模式一样传入一个原始对象的参数的原因。
3)代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。
参考:https://www.cnblogs.com/jaredlam/archive/2011/11/08/2241089.html