前言
今天介绍的是结构型设计模式中的 -- 装饰模式 (Decorator Pattern), 也是装饰器模式. 装饰也就是装点修饰. 例如我们对手机进行装饰, 买了一个新的手机, 先贴个钢化膜. 在带一个壳. 偶尔还在背面贴点贴纸. 装一些挂件. 这些等等行为也就是装饰. 生活中的装饰是如此, 那么编程中的装饰模式又是如何呢?
装饰模式介绍
一, 来由
在我们平常的软件系统中, 经常会面临着向现有的对象添加一些新的功能或者新的职责, 但是呢? 又不能修改现有的类. 以往常用的可能是继承来解决次问题. 但是采用继承来说, 随着扩展功能的增加, 子类会变化的很膨胀. 那么装饰器模式呢就解决这么一个问题, 装饰器模式允许向一个现有的对象添加新的功能职责, 同时又不改变其结构. 将其功能职责划分.
二, 意图
动态地给一个对象添加一些额外的职责. 就增加功能来说, 装饰器模式相比生成子类更为灵活.
三, 案例图
四, 装饰模式代码示例
看上述案例图, 装饰模式包含以下部分组成:
抽象构件角色: 给出一个抽象接口, 以规范准备接收新加的责任
具体构件角色: 继承抽象构件角色, 定义一个将要接收新加责任的类
装饰角色: 继承抽象构件角色, 包含一个构件角色对象的实例, 并且实现抽象构件角色的接口
具体装饰角色: 继承装饰角色, 负责新加责任.
我们继续看手机的案例, 今天新买了一个手机, 需要新加钢化膜, 手机壳, 然后才是一个我想要的手机. 在这儿之后突然又想加一个挂件增加美感. 我们看下如何使用装饰模式来实现手机装饰的问题吧:
- namespace Decorator_Pattern
- {
- class DecoratorPattern
- {
- }
- #region 抽象构件角色 -- 抽象手机 (抽象一个接口, 准备接收新增的责任)=========
- /// <summary>
- /// 手机抽象类
- /// </summary>
- public abstract class Phone
- {
- public abstract void Write();
- }
- #endregion
- #region 具体抽象构件角色 -- 具体手机 (实现抽象接口)===============================
- public class HuaweiV9Phone : Phone
- {
- public override void Write()
- {
- Console.WriteLine("对荣耀 V9 手机开始装饰");
- }
- }
- #endregion
- #region 装饰抽象角色 -- 继承抽象构件角色, 包含一个抽象构件角色对象的实例
- /// <summary>
- /// 装饰角色
- /// </summary>
- public abstract class Decorator : Phone
- {
- public Phone _phone;
- protected Decorator(Phone phone)
- {
- this._phone = phone;
- }
- public override void Write()
- {
- if (_phone!=null)
- {
- _phone.Write();
- }
- }
- }
- #endregion
- #region 具体装饰角色 -- 手机加上钢化膜
- /// <summary>
- /// 具体装饰角色
- /// </summary>
- public class Membrane : Decorator
- {
- public Membrane(Phone phone) : base(phone) { }
- public override void Write()
- {
- base.Write();
- AddMembrane();
- }
- public void AddMembrane()
- {
- Console.WriteLine("手机加上了钢化膜!");
- }
- }
- #endregion
- #region 具体装饰角色 -- 手机加上壳
- /// <summary>
- /// 具体装饰角色
- /// </summary>
- public class Shell : Decorator
- {
- public Shell(Phone phone) : base(phone) { }
- public override void Write()
- {
- base.Write();
- AddShell();
- }
- public void AddShell()
- {
- Console.WriteLine("手机加上了壳!");
- }
- }
- #endregion
- #region 具体装饰角色 -- 手机挂件
- /// <summary>
- /// 具体装饰角色
- /// </summary>
- public class Pendant : Decorator
- {
- public Pendant(Phone phone) : base(phone) { }
- public override void Write()
- {
- base.Write();
- AddPendant();
- }
- public void AddPendant()
- {
- Console.WriteLine("手机加上了挂件!");
- }
- }
- #endregion
- }
- class Program
- {
- static void Main(string[] args)
- {
- // 现在获得了一个手机
- Phone phone = new HuaweiV9Phone();
- // 裸机一个, 先贴个膜
- Decorator membrane = new Membrane(phone);
- membrane.Write();
- Console.WriteLine();
- // 还是觉得不顺眼, 再加个外壳看看
- Decorator membraneShell = new Shell(membrane);
- // 现在我同时有钢化膜和外壳了
- membraneShell.Write();
- Console.WriteLine( );
- // 这时候我觉得还是不要外壳了. 我需要同时又钢化膜和手机挂件
- Decorator membranePendant = new Pendant(membrane);
- membranePendant.Write();
- Console.WriteLine();
- Console.ReadLine();
- }
- }
使用场景及优缺点
一, 使用场景
1, 需要扩展类的功能或者为类增加新增的责任
2, 需要动态增加功能或者撤销功能
二, 优点
1, 装饰类与被装饰类可以独立发展, 不会互相耦合, 极易扩展, 符合开闭原则
2, 装饰模式与继承关系的目的都是要扩展对象的功能, 但是装饰模式可以提供比继承更多的灵活性.
三, 缺点
1, 增加系统复杂度, 更加易于出错, 难于排查错误. 增大了学习与理解的难度.
总结
装饰模式到这里就短暂的介绍完了. 在平常中, 装饰模式使用的情况较多. 一般来说, 我们扩展一个类经常选择继承的方式, 但是由于继承是为类引入静态的特征. 并且随着功能增加的越来越多, 子类会越来越膨胀. 装饰模式是可以替代继承方式的. 前面结构型的设计模式也学习了适配器模式与桥接模式. 再加上今天学习的装饰模式. 我们都需要细细分析其区别及使用场景, 以便于后期使用时不至于混淆其用法. 要用的恰到好处.
只有经历过地狱般的折磨, 才有征服天堂的力量. 只有流过血的手指才能弹出世间的绝唱.
C# 设计模式系列目录
欢迎大家扫描下方二维码, 和我一起踏上设计模式的闯关之路吧!
来源: https://www.cnblogs.com/hulizhong/p/11454474.html