设计模式之Decorator装饰者设计模式

意图 intent :动态地给一个对象添加一些额外的职责。就增加功能来说, Decorator 模式相比生成子类更为灵活。

适用性:1)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。2)处理那些可以撤消的职责。3)当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

 

DefinitionAttach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. 动态的给一个对象添加额外的职责。装饰者使子类扩展功能很灵活的改变。

ParticipantsThe 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.

 

Component是一个abstract类,提供了一个接口。ConcreteComponent类继承自Component,覆盖了Componentoperation函数。Decorator也是一个abstract类,也继承自Component。这部分就类似于Composite设计模式了。Decorator中也有一个component的成员变量。接下来就是两个ConcreteDecorator了,他们非常方便地扩展了ConcreteComponent的功能。ConcreteDecoratorConcreteComponentdecorator,而ConcreteComponent则是ConcreteDecoratordecoratee。另外,从UML图我们可以看出有两种decorator,一种是添加行为,另一种是添加state

我们通常可以使用继承来实现功能的拓展,如果这些需要拓展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时,使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。使用Decorator的理由是:这些功能需要由用户动态决定加入的方式和时机。Decorator提供了“即插即用”的方法,在运行期间决定何时增加何种功能。

下例中的cdecoratee, d1decoratord2d1decoratorDecorator这个设计模式还是有点搞得,比composite要来得复杂。所以建议先看composite,再看decoratorHave fun & good luck

 

Sample code in C#

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

// Decorator pattern -- Structural example

 

using System;

namespace DoFactory.GangOfFour.Decorator.Structural
{

  // MainApp test application

  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.Read();
    }
  }

  // "Component"

  abstract class Component
  {
    public abstract void Operation();
  }

  // "ConcreteComponent"

  class ConcreteComponent : Component
  {
    public override void Operation()
    {
      Console.WriteLine("ConcreteComponent.Operation()");
    }
  }

  // "Decorator"

  abstract class Decorator : Component
  {
    protected Component component;

    public void SetComponent(Component component)
    {
      this.component = component;
    }

    public override void Operation()
    {
      if (component != null)
      {
        component.Operation();
      }
    }
  }

  // "ConcreteDecoratorA"

  class ConcreteDecoratorA : Decorator
  {
    private string addedState;

    public override void Operation()
    {
      base.Operation();
      addedState = "New State";
      Console.WriteLine("ConcreteDecoratorA.Operation()");
    }
  }

  // "ConcreteDecoratorB"

  class ConcreteDecoratorB : Decorator
  {
    public override void Operation()
    {
      base.Operation();
      AddedBehavior();
      Console.WriteLine("ConcreteDecoratorB.Operation()");
    }

    void AddedBehavior()
    {
    }
  }
}

 

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).

// Decorator pattern -- Real World example

 

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Decorator.RealWorld
{

  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      // 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.Read();
    }
  }

  // "Component"

  abstract class LibraryItem
  {
    private int numCopies;

    // Property
    public int NumCopies
    {
      get{ return numCopies; }
      set{ numCopies = value; }
    }

    public abstract void Display();
  }

  // "ConcreteComponent"

  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);
    }
  }

  // "ConcreteComponent"

  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);
    }
  }

  // "Decorator"

  abstract class Decorator : LibraryItem
  {
    protected LibraryItem libraryItem;

    // Constructor
    public Decorator(LibraryItem libraryItem)
    {
      this.libraryItem = libraryItem;
    }

    public override void Display()
    {
      libraryItem.Display();
    }
  }

  // "ConcreteDecorator"

  class Borrowable : Decorator
  {
    protected ArrayList borrowers = new ArrayList();

    // 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);
      }
    }
  }
}

 

Output

Book ------

Author: Worley

Title: Inside ASP.NET

# Copies: 10

 

Video -----

Director: Spielberg

Title: Jaws

# Copies: 23

Playtime: 92

 

 

Making video borrowable:

 

Video -----

Director: Spielberg

Title: Jaws

# Copies: 21

Playtime: 92

 

borrower: Customer #1

borrower: Customer #2

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值