zoukankan      html  css  js  c++  java
  • C#设计模式——装饰者模式

    一、装饰者模式介绍:

    装饰者模式——以对客户透明的方式动态地给一个对象添加额外的职责,采用对象组合而非继承的方式实现了再运行时动态地扩展对象功能的能力,相比生成子类可以更灵活地增加功能,而且可以根据需要扩展多个功能,避免了单独使用继承带来的灵活性差和多子类衍生问题。同时它很好地符合面向对象设计原则中 ”优先使用对象组合而非继承“和”开放-封闭“原则。

    二、背景:

    在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给笔记本添加贴膜,笔记本外设键盘,辅助扇热风扇等,如果此时利用继承来实现的话,就需要定义无数的类,如贴膜笔记本类StickerNoteBook、笔记本外设类PeripheralsNoteBook等,这样就会导致 ”子类爆炸“问题,为了解决这个问题,装饰者模式出现了。

    三、装饰者模式中的各个角色:

    • 抽象构件(NoteBook)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
    • 具体构件(AppNotebook)角色:定义一个将要接收附加责任的类。
    • 装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
    • 具体装饰(Sticker和Peripherals)角色:负责给构件对象 ”贴上“附加的责任。

    三、相关代码:

    1、抽象构件(NoteBook)角色

        /// <summary>
        /// 笔记本抽象类,即装饰者模式中的抽象组件类
        /// </summary>
        public abstract class NoteBook
        {
            public abstract void SayHello();
        }

    2、具体构件(AppNotebook)角色

        /// <summary>
        /// 联想笔记本,即装饰着模式中的具体组件类
        /// </summary>
        public class LenovoNoteBook : NoteBook
        {
            public override void SayHello()
            {
                Console.WriteLine("我是联想笔记本");
            }
        }

    3、装饰(Dicorator)角色

        /// <summary>
        /// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自NoteBook
        /// </summary>
        public abstract class Decorator:NoteBook
        {
            private NoteBook notebook;
            public Decorator(NoteBook n)
            {
                this.notebook = n;
            }
            public override void SayHello()
            {
                if(notebook!=null)
                {
                    notebook.SayHello();
                }
            }
        }

    4、具体装饰(Sticker和Peripherals)角色

        /// <summary>
        /// 贴膜,即具体装饰者
        /// </summary>
        public class Sticker : Decorator
        {
            public Sticker(NoteBook n) : base(n)
            {
            }
            public override void SayHello()
            {
                base.SayHello();
                //添加新行为
                AddSticker();
            }
    
            /// <summary>
            /// 新的行为方法
            /// </summary>
            public void AddSticker()
            {
                Console.WriteLine("给联想笔记本贴膜");
            }
        }
        /// <summary>
        /// 外设,另一个具体装饰者
        /// </summary>
        public class Peripherals : Decorator
        {
            public Peripherals(NoteBook n) : base(n)
            {
            }
            public override void SayHello()
            {
                base.SayHello();
                //添加新行为
                AddPeripherals();
            }
    
            /// <summary>
            /// 新的行为方法
            /// </summary>
            public void AddPeripherals()
            {
                Console.WriteLine("给联想笔记本加外设");
            }
        }

    5、调用

            static void Main(string[] args)
            {
                //创建联想笔记本对象
                NoteBook notebook = new LenovoNoteBook();
                //扩展贴膜行为
                Decorator lenovowithsticker = new Sticker(notebook);
                lenovowithsticker.SayHello();
                Console.WriteLine("=======================");
    
                //扩展增加外设行为
                Decorator lenovowithperipherals = new Peripherals(notebook);
                lenovowithperipherals.SayHello();
                Console.WriteLine("=======================");
    
                //同时扩展贴膜和增加外设行为
                Sticker sticker = new Sticker(notebook);
                Peripherals peripherals = new Peripherals(sticker);
                peripherals.SayHello();
                Console.ReadKey();
            }

    如果需要添加辅助扇热风扇时,此时只需要添加一个继承Decorator的辅助扇热风扇类,从而,装饰者模式扩展性也非常好。

    四、使用场景:

    1. 需要扩展一个类的功能或给一个类增加附加责任。
    2. 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
    3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能

    五、总结:

    优点

    • 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
    • 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
    • 装饰者模式有很好地可扩展性

    缺点

    • 装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。
  • 相关阅读:
    白天写代码,晚上摆地摊!9年前摆地摊学会了这些道理...
    啪啪,打脸了!领导说:try-catch必须放在循环体外!
    阿里巴巴为什么让初始化集合时必须指定大小?
    永远不要使用双花括号初始化实例,否则就会OOM!
    限流的6大狠招,附详细代码和评测结果
    HashMap 的 7 种遍历方式与性能分析!(强烈推荐)
    String性能提升10倍的几个方法!(源码+原理分析)
    9个小技巧让你的 if else看起来更优雅
    用了自定义Banner后,SpringBoot瞬间变的高大上了...
    别再问我 new 字符串创建了几个对象了!我来证明给你看!
  • 原文地址:https://www.cnblogs.com/jiechou/p/9097866.html
Copyright © 2011-2022 走看看