设计模式学习笔记之-Decorator模式

Decorator 模式属于结构型模式。

1.意图

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

 

2.别名

   包装器Wrapper

 

3.动机

     有时候我们希望给某个对象而不是某个类添加一些功能。使用继承机制是添加功能的一种有效途径,但是不够灵活。一种叫较为灵活的方式是将组件嵌入另外一个对象中,由这个对象添加新功能。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明,它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作。

      透明性使得你可以递归的嵌套多个装饰,从而可以添加任意多的功能。

 

4.适用性

l          在不影响其他的对象的情况下,以动态透明的方式给单个对象添加职责

l          处理那些可以撤销的职责

l          当不能采用子类的方法进行扩充时。一种是有可能有大量独立的扩展,使得子类数目爆炸性增长。另外一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类

5.结构

 

 

6.效果

²         优点

n          比静态继承更灵活。可以使用添加和分离的方法,用装饰在运行时刻增加和删除职责

n          避免在层次结构高层的类有太多特征。Decorator模式提供了一种“即用即付”的方法来添加职责。它并不试图在一个复杂的可定制的类中支持所有可以预见的特征

²         缺点

n          Decorator与它的Component不一样。Decorator是一个透明的包装类,如果我们从对象标识的观点出发,一个被装饰了的组件与这个组件是有区别的,因此使用装饰时不应该依赖对象标识

n          有很多小对象,这些对象仅仅在他们相互连接的方式上有所不同,而不是他们的类或者是他们的属性值有所不同。

 

7.实现

(1)     接口的一致性:装饰对象的接口必须与它所装饰的Component的接口是一致的,所有的Concrete Decorator都必须有一个公共的父类

(2)     省略抽象的Decorator类。当你仅仅需要添加一个职责时候,没有必要定义抽象的Decorator类,你常常需要处理现存的类层次结构而不是设计一个新系统,这是你可以把DecoratordComponent转发请求的职责合并到ConcreteDecorator

(3)     保持Component类的简单性,它应集中于定义接口而不是存储数据

(4)     改变对象外壳和改变对象内核:当Component类本来就很庞大时候,使用Decorator模式的代价太高,Strategy模式相对更好一些,在Strategy模式中,组件将它的一些行为转发给一个独立的策略对象,我们可以替换Strategy对象,从而改变或者扩充组件的功能(基于Strategy的方法可能需要修改component组件以适应新的扩充,另外一方面,一个策略可以有自己特定的接口,而装饰的接口必须与组件接口一致

 

8.相关模式

Adapter模式:Decorator 模式 不同于Adapter模式,因为装饰仅仅改变了对象的职责而不改变它的接口,而适配器将给对象一个全新的接口

Composite模式:可以将装饰视为一个退化的,仅有一个组件的组合,然而装饰仅仅给对象添加一些额外的职责他的目的不在对象聚集

Strategy模式:用一个装饰可以改变对象的外表,用Strategty模式可以使你改变对象的内核

 

9.应用实例—Java I/O包中的Decorator模式

 

(1)     OutputStream是一个抽象类,它是所有输出流的公共父类,其源代码如下:

  

  public abstract class OutputStream implements Closeable, Flushable {

  public abstract void write(int b) throws IOException;

  ...

  }

  

它定义了write(int b)的抽象方法。这相当于Decorator模式中的Component类。

(2)     ByteArrayOutputStream为例:

 

  public class ByteArrayOutputStream extends OutputStream {

  protected byte buf[];

  protected int count;

  public ByteArrayOutputStream() {

  this(32);

  }

  public ByteArrayOutputStream(int size) {

  if (size 0) {

  throw new IllegalArgumentException("Negative initial size: " + size);

  }

  buf = new byte[size];

  }

  public synchronized void write(int b) {

  int newcount = count + 1;

  if (newcount buf.length) {

  byte newbuf[] = new byte[Math.max(buf.length << 1, newcount)];

  System.arraycopy(buf, 0, newbuf, 0, count);

  buf = newbuf;

  }

  buf[count] = (byte)b;

  count = newcount;

  }

  ...

  }

  

它实现了OutputStream中的write(int b)方法,因此我们可以用来创建输出流的对象,并完成特定格式的输出。它相当于Decorator模式中的ConcreteComponent类。

(3)     FilterOutputStream,代码如下:

  

  public class FilterOutputStream extends OutputStream {

  protected OutputStream out;

  public FilterOutputStream(OutputStream out) {

  this.out = out;

  }

  public void write(int b) throws IOException {

  out.write(b);

  }

  ...

  }

  

同样,它也是从OutputStream继续。但是,它的构造函数需要传递一个OutputStream的引用给它,并且它将保存对此对象的引用。这个FilterOutputStream类相当于Decorator模式中的Decorator类,它的write(int b)方法只是简单的调用了传入的流的write(int b)方法,而没有做更多的处理,因此它本质上没有对流进行装饰,所以继续它的子类必须覆盖此方法,以达到装饰的目的。

(4)     BufferedOutputStream DataOutputStreamFilterOutputStream的两个子类,它们相当于Decorator模式中的ConcreteDecorator,并对传入的输出流做了不同的装饰。以BufferedOutputStream类为例:

 

  public class BufferedOutputStream extends FilterOutputStream {

  ...

  private void flushBuffer() throws IOException {

  if (count 0) {

  out.write(buf, 0, count);

  count = 0;

  }

  }

  public synchronized void write(int b) throws IOException {

  if (count = buf.length) {

  flushBuffer();

  }

  buf[count++] = (byte)b;

  }

  ...

  }

  

  这个类提供了一个缓存机制,等到缓存的容量达到一定的字节数时才写入输出流。首先它继续了FilterOutputStream,并且覆盖了父类的write(int b)方法,在调用输出流写出数据前都会检查缓存是否已满,假如未满,则不写。这样就实现了对输出流对象动态的添加新功能的目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值