Design Pattern - Decorator(C#)

来源:互联网 发布:牛贝微信淘宝客官网 编辑:程序博客网 时间:2024/04/28 09:49

Definition

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Participants

    The classes and/or objects participating in this pattern are:

  • Component  (LibraryItem)
    • Defines the interface for objects that can have responsibilities added to them dynamically.
  • ConcreteComponent  (Book, Video)
    • Defines an object to which additional responsibilities can be attached.
  • Decorator  (Decorator)
    • Maintains a reference to a Component object and defines an interface that conforms to Component's interface.
  • ConcreteDecorator  (Borrowable)
    • Adds responsibilities to the component.

Sample Code in C#


This structural code demonstrates the Decorator pattern which dynamically adds extra functionality to an existing object.

// --------------------------------------------------------------------------------------------------------------------// <copyright company="Chimomo's Company" file="Program.cs">// Respect the work.// </copyright>// <summary>// Structural Decorator Design Pattern.// </summary>// --------------------------------------------------------------------------------------------------------------------namespace CSharpLearning{    using System;    /// <summary>    /// Startup class for Structural Decorator Design Pattern.    /// </summary>    internal static class Program    {        #region Methods        /// <summary>        /// Entry point into console application.        /// </summary>        private static void Main()        {            // Create ConcreteComponent and two Decorators            var c = new ConcreteComponent();            var d1 = new ConcreteDecoratorA();            var d2 = new ConcreteDecoratorB();            // Link decorators            d1.SetComponent(c);            d2.SetComponent(d1);            d2.Operation();        }        #endregion    }    /// <summary>    /// The 'Component' abstract class    /// </summary>    internal abstract class Component    {        #region Public Methods and Operators        /// <summary>        /// The operation.        /// </summary>        public abstract void Operation();        #endregion    }    /// <summary>    /// The 'ConcreteComponent' class    /// </summary>    internal class ConcreteComponent : Component    {        #region Public Methods and Operators        /// <summary>        /// The operation.        /// </summary>        public override void Operation()        {            Console.WriteLine("ConcreteComponent.Operation()");        }        #endregion    }    /// <summary>    /// The 'Decorator' abstract class    /// </summary>    internal abstract class Decorator : Component    {        #region Fields        /// <summary>        /// The component.        /// </summary>        protected Component Component;        #endregion        #region Public Methods and Operators        /// <summary>        /// The operation.        /// </summary>        public override void Operation()        {            if (this.Component != null)            {                this.Component.Operation();            }        }        /// <summary>        /// The set component.        /// </summary>        /// <param name="component">        /// The component.        /// </param>        public void SetComponent(Component component)        {            this.Component = component;        }        #endregion    }    /// <summary>    /// The 'ConcreteDecoratorA' class    /// </summary>    internal class ConcreteDecoratorA : Decorator    {        #region Public Methods and Operators        /// <summary>        /// The operation.        /// </summary>        public override void Operation()        {            base.Operation();            Console.WriteLine("ConcreteDecoratorA.Operation()");        }        #endregion    }    /// <summary>    /// The 'ConcreteDecoratorB' class    /// </summary>    internal class ConcreteDecoratorB : Decorator    {        #region Public Methods and Operators        /// <summary>        /// The operation.        /// </summary>        public override void Operation()        {            base.Operation();            this.AddedBehavior();            Console.WriteLine("ConcreteDecoratorB.Operation()");        }        #endregion        #region Methods        /// <summary>        /// The added behavior.        /// </summary>        private void AddedBehavior()        {        }        #endregion    }}// Output:/*ConcreteComponent.Operation()ConcreteDecoratorA.Operation()ConcreteDecoratorB.Operation()*/


This real-world code demonstrates the Decorator pattern in which 'borrowable' functionality is added to existing library items (books and videos).

// --------------------------------------------------------------------------------------------------------------------// <copyright company="Chimomo's Company" file="Program.cs">// Respect the work.// </copyright>// <summary>// Real-World Decorator Design Pattern.// </summary>// --------------------------------------------------------------------------------------------------------------------namespace CSharpLearning{    using System;    using System.Collections.Generic;    /// <summary>    /// Startup class for Real-World Decorator Design Pattern.    /// </summary>    internal static class Program    {        #region Methods        /// <summary>        /// Entry point into console application.        /// </summary>        private static void Main()        {            // Create book            var book = new Book("Worley", "Inside ASP.NET", 10);            book.Display();            // Create video            var video = new Video("Spielberg", "Jaws", 23, 92);            video.Display();            // Make video borrowable, then borrow and display            Console.WriteLine("\nMaking video borrowable:");            var borrowvideo = new Borrowable(video);            borrowvideo.BorrowItem("Customer #1");            borrowvideo.BorrowItem("Customer #2");            borrowvideo.Display();        }        #endregion    }    /// <summary>    /// The 'Component' abstract class    /// </summary>    internal abstract class LibraryItem    {        // Property        #region Public Properties        /// <summary>        /// Gets or sets the number of copies.        /// </summary>        public int NumCopies { get; set; }        #endregion        #region Public Methods and Operators        /// <summary>        /// The display.        /// </summary>        public abstract void Display();        #endregion    }    /// <summary>    /// The 'ConcreteComponent' class    /// </summary>    internal class Book : LibraryItem    {        #region Fields        /// <summary>        /// The author.        /// </summary>        private string author;        /// <summary>        /// The title.        /// </summary>        private string title;        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Book"/> class.        /// </summary>        /// <param name="author">        /// The author.        /// </param>        /// <param name="title">        /// The title.        /// </param>        /// <param name="numCopies">        /// The number of copies.        /// </param>        public Book(string author, string title, int numCopies)        {            this.author = author;            this.title = title;            this.NumCopies = numCopies;        }        #endregion        #region Public Methods and Operators        /// <summary>        /// The display.        /// </summary>        public override void Display()        {            Console.WriteLine("\nBook ------ ");            Console.WriteLine(" Author: {0}", this.author);            Console.WriteLine(" Title: {0}", this.title);            Console.WriteLine(" # Copies: {0}", this.NumCopies);        }        #endregion    }    /// <summary>    /// The 'ConcreteComponent' class    /// </summary>    internal class Video : LibraryItem    {        #region Fields        /// <summary>        /// The director.        /// </summary>        private string director;        /// <summary>        /// The play time.        /// </summary>        private int playTime;        /// <summary>        /// The title.        /// </summary>        private string title;        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Video"/> class.        /// </summary>        /// <param name="director">        /// The director.        /// </param>        /// <param name="title">        /// The title.        /// </param>        /// <param name="numCopies">        /// The number of copies.        /// </param>        /// <param name="playTime">        /// The play time.        /// </param>        public Video(string director, string title, int numCopies, int playTime)        {            this.director = director;            this.title = title;            this.NumCopies = numCopies;            this.playTime = playTime;        }        #endregion        #region Public Methods and Operators        /// <summary>        /// The display.        /// </summary>        public override void Display()        {            Console.WriteLine("\nVideo ----- ");            Console.WriteLine(" Director: {0}", this.director);            Console.WriteLine(" Title: {0}", this.title);            Console.WriteLine(" # Copies: {0}", this.NumCopies);            Console.WriteLine(" Playtime: {0}\n", this.playTime);        }        #endregion    }    /// <summary>    /// The 'Decorator' abstract class    /// </summary>    internal abstract class Decorator : LibraryItem    {        #region Fields        /// <summary>        /// The library item.        /// </summary>        protected readonly LibraryItem LibraryItem;        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Decorator"/> class.        /// </summary>        /// <param name="libraryItem">        /// The library item.        /// </param>        protected Decorator(LibraryItem libraryItem)        {            this.LibraryItem = libraryItem;        }        #endregion        #region Public Methods and Operators        /// <summary>        /// The display.        /// </summary>        public override void Display()        {            this.LibraryItem.Display();        }        #endregion    }    /// <summary>    /// The 'ConcreteDecorator' class    /// </summary>    internal class Borrowable : Decorator    {        #region Fields        /// <summary>        /// The borrowers.        /// </summary>        protected readonly List<string> Borrowers = new List<string>();        #endregion        // Constructor        #region Constructors and Destructors        /// <summary>        /// Initializes a new instance of the <see cref="Borrowable"/> class.        /// </summary>        /// <param name="libraryItem">        /// The library item.        /// </param>        public Borrowable(LibraryItem libraryItem)            : base(libraryItem)        {        }        #endregion        #region Public Methods and Operators        /// <summary>        /// The borrow item.        /// </summary>        /// <param name="name">        /// The name.        /// </param>        public void BorrowItem(string name)        {            this.Borrowers.Add(name);            this.LibraryItem.NumCopies--;        }        /// <summary>        /// The display.        /// </summary>        public override void Display()        {            base.Display();            foreach (string borrower in this.Borrowers)            {                Console.WriteLine(" borrower: " + borrower);            }        }        /// <summary>        /// The return item.        /// </summary>        /// <param name="name">        /// The name.        /// </param>        public void ReturnItem(string name)        {            this.Borrowers.Remove(name);            this.LibraryItem.NumCopies++;        }        #endregion    }}// Output:/*Book ------ Author: Worley Title: Inside ASP.NET # Copies: 10Video ----- Director: Spielberg Title: Jaws # Copies: 23 Playtime: 92Making video borrowable:Video ----- Director: Spielberg Title: Jaws # Copies: 21 Playtime: 92 borrower: Customer #1 borrower: Customer #2*/