zoukankan      html  css  js  c++  java
  • C#面向对象设计模式纵横谈 笔记10 Decorator 装饰(结构型模式)

    子类复子类,子类何其多

       假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能:比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等。 

    // 抽象坦克
    public abstract class Tank
    {
      public abstract Shot();
      public abstract Run();
    }

    //各种不同功能的组合
    public class T50A: T50, IA {…}
    public class T50B: T50, IB {…}
    public class T50C: T50, IC {…}
    public class T50AB: T50, IA, IB {…}
    public class T50BC: T50, IB, IC {…}
    public class T50ABC: T50, IA, IB, IC{...}              

    //各种型号
    public class T50: Tank {……}
    public class T75: Tank {……}
    public class T90: Tank {……}

    动机(Motivation

       上述描述的问题根源在于我们过度地使用了继承来扩展对象的功能,由于继承为类型引入的静态特质(在编译时确定),使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。

       如何使对象功能的扩展能够根据需要来动态地运行时实现?同时避免扩展功能的增多带来的子类膨胀问题?从而使得任何功能扩展变化所导致的影响将为最低?

    意图(Intent

    动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。      ——  《设计模式》GoF

    例说Decorator应用 ——Codes in .NET

    1)客户程序

        class Program
    {
    static void Main(string[] args)
    {
    Tank tank
    = new T50();
    //扩展红外
    DecoratorA da = new DecoratorA(tank);

    //扩展红外,卫星定位
    DecoratorB db = new DecoratorB(da);
    db.Shot();
    }
    }


    2)抽象Tank

        public abstract class Tank
    {
    public abstract void Shot();
    public abstract void Run();
    }


    3)装饰基类

        /// <summary>
    /// 接口继承,行为像Tank。但不是Tank
    /// </summary>
    public abstract class Decorator : Tank
    {
    /// <summary>
    /// Has-A 对象组合
    /// </summary>
    private Tank tank;

    public Decorator(Tank tank)
    {
    this.tank = tank;
    }

    public override void Shot()
    {
    tank.Shot();
    }
    public override void Run()
    {
    tank.Run();
    }
    }


    4)装饰类

        /// <summary>
    /// 对红外功能的扩展
    /// </summary>
    public class DecoratorA : Decorator
    {
    public DecoratorA(Tank tank)
    :
    base(tank)
    { }

    public override void Shot()
    {
    //红外功能扩展
    this.ShotA();

    //do shot...
    base.Shot();
    }
    public override void Run()
    {
    //红外功能扩展
    this.RunA();

    //do run...
    base.Run();
    }

    public void ShotA()
    { }
    public void RunA()
    { }
    }

    /// <summary>
    /// 对卫星定位的扩展
    /// </summary>
    public class DecoratorB : Decorator
    {
    public DecoratorB(Tank tank)
    :
    base(tank)
    { }

    public override void Shot()
    {
    //卫星定位功能扩展
    this.ShotB();

    //do shot...
    base.Shot();
    }
    public override void Run()
    {
    //卫星定位功能扩展
    this.RunB();

    //do run...
    base.Run();
    }

    public void ShotB()
    { }
    public void RunB()
    { }
    }


    5)具体Tank

        public class T50 : Tank
    {
    public override void Shot()
    { }
    public override void Run()
    { }
    }

    public class T75 : Tank
    {
    public override void Shot()
    { }
    public override void Run()
    { }
    }

    结构(Structure

    Decorator模式的几个要点

    1)通过采用组合、而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的灵活性差多子类衍生问题

    2)Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类应该透明——换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。

    3)Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或者多个Decorator对象来装饰一个Component对象,且装饰后的对象仍然是一个Component对象。

    4)Decorator模式并非解决多子类衍生的多继承问题,Decorator模式应用的要点在于解决主体类在多个方向上的扩展功能”——是为装饰的含义。

    .NET框架中的Decorator应用

    举例:特别的地方是,装饰类直接继承抽象类Stream,没有了上面的“Decorator”类

    MemoryStream ms = new MemoryStream(new byte[] { 119, 250, 110, 120 });

    //扩展缓冲功能
    BufferedStream buff = new BufferedStream(ms);
    //扩展加密功能
    ICryptoTransform transform= null;
    CryptoStream crypto
    = new CryptoStream(ms, transform, CryptoStreamMode.Read);

    推荐资源

    1)《设计模式:可复用面向对象软件的基础》GoF

    2)《面向对象分析与设计》Grady Booch

    3)《敏捷软件开发:原则、模式与实践》Robert C. Martin

    4)《重构:改善既有代码的设计》Martin Fowler

    5)Refactoring to PatternsJoshua Kerievsky

  • 相关阅读:
    最全的 Twitter Bootstrap 开发资源清单
    jQuery布局插件UI Layout简介及使用方法
    SQLcode错误代码汇总和sqlstate=37000的解决方案
    JQUERY插件学习之jQuery UI
    如何判断/检查一个集合(List<string>)中是否有重复的元素
    反射原理及简介
    C# 获取文件夹下的所有文件的文件名
    委托编程指南
    模块封装与程序集
    Redis Lock
  • 原文地址:https://www.cnblogs.com/lujiao_cs/p/2174206.html
Copyright © 2011-2022 走看看