装饰模式(Decorator Pattern)

装饰模式(Decorator Pattern

一句话

继承一个抽象类,加上自己的特点,然后再使自己也变成抽象类,然后让子类继承的模式,叫装饰模式

意图

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

结构图

<shapetype id="_x0000_t75" stroked="f" filled="f" path="[email protected]@[email protected]@[email protected]@[email protected]@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 323.25pt; HEIGHT: 267pt" alt="" type="#_x0000_t75"><imagedata o:href="http://terrylee.cnblogs.com/images/cnblogs_com/terrylee/Decorator_02.gif" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.gif"></imagedata></shape>

装饰模式(Decorator Pattern)

生活中的例子

我们还是拿咖啡来举例子,现在有需要泡一杯咖啡出来。泡咖啡的几个步骤:

1. 磨咖啡豆

2. 煮。

先定义一个接口

public interface MakeCoffee
{
  public void milling();//

public void cook();//

}

//来一杯蓝山咖啡

public class Blue_Mountain_Coffee : MakeCoffee

{
  public void milling()

{
    //代码略
  }

  public void cook()

{
    //代码略
  }

}

现在要来杯卡布奇诺Cappuccino,那么需要加入“做泡泡”的行为。

如果是按一般的方法,在接口内加入“做泡泡(Bubbles)”的行为。但是这样的话,做其他咖啡的时候都必须去实现Bubbles的行为,这样代码就很罗嗦。

所以,我们引入一个简单的处理,装饰模式(Decorator Pattern

public abstract class Decorator : MakeCoffee

{

  public void milling();

  public void cook();

  public void Bubbles();

}

所有要做泡泡的咖啡都来继承这个类。

//来一杯卡布奇诺咖啡

public class Cappuccino : MakeCoffee

{
  public void milling()

{
    //代码略
  }

  public void cook()

{
    //代码略
  }

  public void Bubbles()

{
    //代码略
  }

  public void MakeCoffee()

{
    milling();//磨咖啡豆

cook();//

Bubbles();//做泡泡
  }

}

好了,打完收工。

装饰模式(Decorator Pattern)

装饰模式解说

我们分析一下这样会带来什么好处?首先对于扩展功能已经实现了真正的动态增加,只在需要某种功能的时候才进行包装;其次,如果再出现一种新的扩展功能,只需要增加一个对应的包装子类(注意:这一点任何时候都是避免不了的),而无需再进行很多子类的继承,不会出现子类的膨胀,同时Decorator模式也很好的符合了面向对象设计原则中的“优先使用对象组合而非继承”和“开放-封闭”原则。

.NET中的装饰模式

1.NETDecorator模式一个典型的运用就是关于Stream,它存在着如下的类结构:

<shape id="_x0000_i1026" style="WIDTH: 470.25pt; HEIGHT: 183pt" alt="" type="#_x0000_t75"><imagedata o:href="http://terrylee.cnblogs.com/images/cnblogs_com/terrylee/Decorator_081.jpg" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image002.jpg"></imagedata></shape>

装饰模式(Decorator Pattern)

可以看到, BufferedStreamCryptoStream其实就是两个包装类,这里的Decorator模式省略了抽象装饰角色(Decorator),示例代码如下:

class Program

{

public static void <place w:st="on">Main</place>(string[] args)

{

MemoryStream ms =

new MemoryStream(new byte[] { 100,456,864,222,567});

//扩展了缓冲的功能

BufferedStream buff = new BufferedStream(ms);

//扩展了缓冲,加密的功能

CryptoStream crypto = new CryptoStream(buff);

}

}

通过反编译,可以看到BufferedStream类的代码(只列出部分),它是继承于Stream类:

public sealed class BufferedStream : Stream

{

// Methods

private BufferedStream();

public BufferedStream(Stream stream);

public BufferedStream(Stream stream, int bufferSize);

// Fields

private int _bufferSize;

private Stream _s;

}

2.在Enterprise Library中的DAAB中有一个DbCommandWrapper的包装类,它实现了对IDbCommand类的包装并提供了参数处理的功能。结构图如下:

<shape id="_x0000_i1027" style="WIDTH: 460.5pt; HEIGHT: 197.25pt" alt="" type="#_x0000_t75"><imagedata o:href="http://terrylee.cnblogs.com/images/cnblogs_com/terrylee/Decorator_091.jpg" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.jpg"></imagedata></shape>

装饰模式(Decorator Pattern)

示意性代码如下:

public abstract class DBCommandWrapper : MarshalByRefObject, IDisposable

{

}

public class SqlCommandWrapper : DBCommandWrapper

{

}

public class OracleCommandWrapper : DBCommandWrapper

{

}

效果及实现要点

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

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

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

4.对于Decorator模式在实际中的运用可以很灵活。如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。

<shape id="_x0000_i1028" style="WIDTH: 256.5pt; HEIGHT: 211.5pt" alt="" type="#_x0000_t75"><imagedata o:href="http://terrylee.cnblogs.com/images/cnblogs_com/terrylee/Decorator_101.jpg" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image004.jpg"></imagedata></shape>

装饰模式(Decorator Pattern)

如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把DecoratorConcreteDecorator的责任合并成一个类。

<shape id="_x0000_i1029" style="WIDTH: 356.25pt; HEIGHT: 126pt" alt="" type="#_x0000_t75"><imagedata o:href="http://terrylee.cnblogs.com/images/cnblogs_com/terrylee/Decorator_111.jpg" src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.jpg"></imagedata></shape>

装饰模式(Decorator Pattern)

5Decorator模式的优点是提供了比继承更加灵活的扩展,通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。

6.由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

适用性

在以下情况下应当使用装饰模式:

1.需要扩展一个类的功能,或给一个类增加附加责任。

2.需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。

总结

Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。