设计模式学习之路——Decorator装饰模式(结构模式)

子类复子类,子类何其多

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

动机(Motivation)

上述描述的问题根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?

意图(Intent)

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

——《设计模式》GoF

结构(Structure)

image

 

代码结构

using System;



namespace Decorator.Structural

{

    /// <summary>

    /// MainApp startup class for Structural

    /// Decorator Design Pattern.

    /// </summary>

    class MainApp

    {

        static void Main()

        {

            // Create ConcreteComponent and two Decorators

            ConcreteComponent c = new ConcreteComponent();

            ConcreteDecoratorA d1 = new ConcreteDecoratorA();

            ConcreteDecoratorB d2 = new ConcreteDecoratorB();



            // Link decorators

            d1.SetComponent(c);

            d2.SetComponent(d1);



            d2.Operation();

            // Wait for user

            Console.ReadKey();

        }

    }



    /// <summary>

    /// The 'Component' abstract class

    /// </summary>

    abstract class Component

    {

        public abstract void Operation();

    }



    /// <summary>

    /// The 'ConcreteComponent' class

    /// </summary>

    class ConcreteComponent : Component

    {

        public override void Operation()

        {

            Console.WriteLine("ConcreteComponent.Operation()");

        }

    }



    /// <summary>

    /// The 'Decorator' abstract class

    /// </summary>

    abstract class Decorator : Component

    {

        protected Component component;

        public void SetComponent(Component component)

        {

            this.component = component;

        }

        public override void Operation()

        {

            if (component != null)

            {

                component.Operation();

            }

        }

    }



    /// <summary>

    /// The 'ConcreteDecoratorA' class

    /// </summary>

    class ConcreteDecoratorA : Decorator

    {

        public override void Operation()

        {

            base.Operation();

            Console.WriteLine("ConcreteDecoratorA.Operation()");

        }

    }



    /// <summary>

    /// The 'ConcreteDecoratorB' class

    /// </summary>

    class ConcreteDecoratorB : Decorator

    {

        public override void Operation()

        {

            base.Operation();

            AddedBehavior();

            Console.WriteLine("ConcreteDecoratorB.Operation()");

        }

        void AddedBehavior()

        {

        }

    }

}

输出:

image

 

代码示例:

class Program

    {

        static void Main(string[] args)

        {

            // Create book

            Book book = new Book("Worley", "Inside ASP.NET", 10);

            book.Display();



            // Create video

            Video video = new Video("Spielberg", "Jaws", 23, 92);

            video.Display();



            // Make video borrowable, then borrow and display

            Console.WriteLine("\nMaking video borrowable:");



            Borrowable borrowvideo = new Borrowable(video);

            borrowvideo.BorrowItem("Customer #1");

            borrowvideo.BorrowItem("Customer #2");



            borrowvideo.Display();



            // Wait for user

            Console.ReadKey();



        }

    }



    /// <summary>

    /// The 'Component' abstract class

    /// </summary>

    abstract class LibraryItem

    {

        private int _numCopies;



        // Property

        public int NumCopies

        {

            get { return _numCopies; }

            set { _numCopies = value; }

        }



        public abstract void Display();

    }



    /// <summary>

    /// The 'ConcreteComponent' class

    /// </summary>

    class Book : LibraryItem

    {

        private string _author;

        private string _title;



        // Constructor

        public Book(string author, string title, int numCopies)

        {

            this._author = author;

            this._title = title;

            this.NumCopies = numCopies;

        }



        public override void Display()

        {

            Console.WriteLine("\nBook ------ ");

            Console.WriteLine(" Author: {0}", _author);

            Console.WriteLine(" Title: {0}", _title);

            Console.WriteLine(" # Copies: {0}", NumCopies);

        }

    }



    /// <summary>

    /// The 'ConcreteComponent' class

    /// </summary>

    class Video : LibraryItem

    {

        private string _director;

        private string _title;

        private int _playTime;



        // Constructor

        public Video(string director, string title,

          int numCopies, int playTime)

        {

            this._director = director;

            this._title = title;

            this.NumCopies = numCopies;

            this._playTime = playTime;

        }



        public override void Display()

        {

            Console.WriteLine("\nVideo ----- ");

            Console.WriteLine(" Director: {0}", _director);

            Console.WriteLine(" Title: {0}", _title);

            Console.WriteLine(" # Copies: {0}", NumCopies);

            Console.WriteLine(" Playtime: {0}\n", _playTime);

        }

    }



    /// <summary>

    /// The 'Decorator' abstract class

    /// </summary>

    abstract class Decorator : LibraryItem

    {

        protected LibraryItem libraryItem;



        // Constructor

        public Decorator(LibraryItem libraryItem)

        {

            this.libraryItem = libraryItem;

        }



        public override void Display()

        {

            libraryItem.Display();

        }

    }



    /// <summary>

    /// The 'ConcreteDecorator' class

    /// </summary>

    class Borrowable : Decorator

    {

        protected List<string> borrowers = new List<string>();



        // Constructor

        public Borrowable(LibraryItem libraryItem)

            : base(libraryItem)

        {

        }



        public void BorrowItem(string name)

        {

            borrowers.Add(name);

            libraryItem.NumCopies--;

        }



        public void ReturnItem(string name)

        {

            borrowers.Remove(name);

            libraryItem.NumCopies++;

        }



        public override void Display()

        {

            base.Display();



            foreach (string borrower in borrowers)

            {

                Console.WriteLine(" borrower: " + borrower);

            }

        }

    }

输出:

image

 

Decorator模式的几个要点

  • 通过采用组合、而非继承的手法, Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
  • Component类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Component类应该透明——换言之Component类无需知道Decorator类,Decorator类是从外部来扩展Component类的功能。
  • Decorator类在接口上表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另外一个Component类。我们可以使用一个或者多个Decorator对象来“装饰”一个Component对象,且装饰后的对象仍然是一个Component对象。
  • Decorator模式并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。

.NET框架中的Decorator应用

image

你可能感兴趣的:(Decorator)