装饰器模式,其代码结构和桥接模式很相似,不过解决的问题不尽相同

本次,我们拿Java IO类库来举例说明装饰器模式的使用

Java中的IO类库非常庞大,如果对IO类进行分类,可以基本分为

图片

而且根据这四个版本的分类,进行扩展出了很多的子类了

图片

那么,实际使用中,并不是直接去创建子类,而是要按照如下的使用方式

InputStream in = new FileInputStream(“/user/test.txt”);

InputStream bin = new BufferInputStream(in);

为什么创建一个BufferInputStream需要创建一个FileInputStream对象呢?

为什么不是直接创建BufferInputStream对象呢?

如果基于继承的话,我们在FileInputStream上,设置一个子类,BufferedInputStream的话,也可以

像支持基本数据类型的DataInputStream类,也可以直接继承FileInputStream类就行

但是如果,我们需要一个既能支持缓存,Buffered,也能读取基本数据类型的话,难道要创建一个子类BufferedDataFileInputStream吗?

那么两两组合,会导致多少个组合子类的出现啊

于是出现了基于装饰器的设计方案

我们将继承关系改为组合关系来解决

这样就是利用了简单的组合来增强直接使用了父类的实现

当然,支持解决我们上面说的组合子类的问题

InputStream in  = new FileInputStream(“/test/test.txt”)

InputStream bin  = new BufferedInputStream(in)

DataInputStream din = new DataInputStream(bin);

din.readInt();

这样,其既支持缓存,又可以按照基本数据类型来进行读取

其和代理模式,有异曲同工之妙

在代理类中,通过生产代理类,来增强原有类的逻辑

在装饰器模式的子类中,也可以增强原始类的原有逻辑

// 代理模式的代码结构(下面的接口也可以替换成抽象类)

public interface IA {

  void f();

}

public class A impelements IA {

  public void f() { //… }

}

public class AProxy impements IA {

  private IA a;

  public AProxy(IA a) {

    this.a = a;

  }

  

  public void f() {

    // 新添加的代理逻辑

    a.f();

    // 新添加的代理逻辑

  }

}

// 装饰器模式的代码结构(下面的接口也可以替换成抽象类)

public interface IA {

  void f();

}

public class A impelements IA {

  public void f() { //… }

}

public class ADecorator impements IA {

  private IA a;

  public ADecorator(IA a) {

    this.a = a;

  }

  

  public void f() {

    // 功能增强代码

    a.f();

    // 功能增强代码

  }

}

而且,在实际使用BufferedInputStream等类,并没有去直接使用InputStream,而InputStream这个抽象类中有很多默认的实现

为什么呢

如果直接使用了InputStream的功能,那么就没法去委托了

也就是传入了BufferedInputStream的实现,也没有直接去使用这个实现类的缓存红利

而且装饰器类只需要实现增强的方法就可以了,其他方法继承父类的默认实现

那么本章就讲完了

装饰器模式为了解决继承关系过于复杂的问题,使用了组合来代替继承

为了给原始类增强功能,而且可以嵌套使用多个装饰器

装饰器模式,其代码结构和桥接模式很相似,不过解决的问题不尽相同

本次,我们拿Java IO类库来举例说明装饰器模式的使用

Java中的IO类库非常庞大,如果对IO类进行分类,可以基本分为

图片

而且根据这四个版本的分类,进行扩展出了很多的子类了

图片

那么,实际使用中,并不是直接去创建子类,而是要按照如下的使用方式

InputStream in = new FileInputStream(“/user/test.txt”);

InputStream bin = new BufferInputStream(in);

为什么创建一个BufferInputStream需要创建一个FileInputStream对象呢?

为什么不是直接创建BufferInputStream对象呢?

如果基于继承的话,我们在FileInputStream上,设置一个子类,BufferedInputStream的话,也可以

像支持基本数据类型的DataInputStream类,也可以直接继承FileInputStream类就行

但是如果,我们需要一个既能支持缓存,Buffered,也能读取基本数据类型的话,难道要创建一个子类BufferedDataFileInputStream吗?

那么两两组合,会导致多少个组合子类的出现啊

于是出现了基于装饰器的设计方案

我们将继承关系改为组合关系来解决

这样就是利用了简单的组合来增强直接使用了父类的实现

当然,支持解决我们上面说的组合子类的问题

InputStream in  = new FileInputStream(“/test/test.txt”)

InputStream bin  = new BufferedInputStream(in)

DataInputStream din = new DataInputStream(bin);

din.readInt();

这样,其既支持缓存,又可以按照基本数据类型来进行读取

其和代理模式,有异曲同工之妙

在代理类中,通过生产代理类,来增强原有类的逻辑

在装饰器模式的子类中,也可以增强原始类的原有逻辑

// 代理模式的代码结构(下面的接口也可以替换成抽象类)

public interface IA {

  void f();

}

public class A impelements IA {

  public void f() { //… }

}

public class AProxy impements IA {

  private IA a;

  public AProxy(IA a) {

    this.a = a;

  }

  

  public void f() {

    // 新添加的代理逻辑

    a.f();

    // 新添加的代理逻辑

  }

}

// 装饰器模式的代码结构(下面的接口也可以替换成抽象类)

public interface IA {

  void f();

}

public class A impelements IA {

  public void f() { //… }

}

public class ADecorator impements IA {

  private IA a;

  public ADecorator(IA a) {

    this.a = a;

  }

  

  public void f() {

    // 功能增强代码

    a.f();

    // 功能增强代码

  }

}

而且,在实际使用BufferedInputStream等类,并没有去直接使用InputStream,而InputStream这个抽象类中有很多默认的实现

为什么呢

如果直接使用了InputStream的功能,那么就没法去委托了

也就是传入了BufferedInputStream的实现,也没有直接去使用这个实现类的缓存红利

而且装饰器类只需要实现增强的方法就可以了,其他方法继承父类的默认实现

那么本章就讲完了

装饰器模式为了解决继承关系过于复杂的问题,使用了组合来代替继承

为了给原始类增强功能,而且可以嵌套使用多个装饰器

发表评论

邮箱地址不会被公开。 必填项已用*标注