设计模式 六月 03, 2021

装饰器模式

文章字数 3.9k 阅读约需 4 mins. 阅读次数 0

装饰器模式

解决问题

为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

方案

动态地给一个对象添加一些额外的职责, 通过创建一个包装对象,也就是装饰来包裹真实的对象。

结构

装饰器模式

  • 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。

  • 具体组件角色(ConcreteComponent) :被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责

  • 抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口

  • 具体装饰器角色(ConcreteDecorator):向组件添加职责。

public abstract class Component{
    // 抽象地方法
    public abstract void cost();
}

public class ConcreteComponent extends Component{
    @Override
    public void cost(){
        // do something ...
    }
}

public abstract class Decorator extends Component{
    private Component component = null;
    public Decorator(Component component){
        this.component = component;
    }
    @Override
    public void cost(){
        this.component.cost();
    }
}
public class ConcreteDecorator extends Decorator{
    public ConcreteDecorator(Component component){
        super(component);
    }

    // 定义自己的修饰逻辑
    private void decorateMethod(){
        // do somethind ... 
    }

    // 重写父类的方法
    public void cost(){
        this.decorateMethod();
        super.cost();
    }
}

public class DecoratorDemo{
    public static void main(String[] args){
        Component component = new ConcreteComponent();
        // 第一次修饰,比如,加鸡蛋,加1块
        component = new ConcreteDecorator(component);
        // 第二次修饰,比如,加烤肠,加2块
        component = new ConcreteDecorator(component);
        // 修饰后运行,将钱加在一起
        component.cost();
    }
}

适用性

侧重点在于灵活的增加需要的属性.装饰顾名思义,可以凭借自己的喜好,随意添加自己想要的装饰.我可以装饰一个物件,可以一个接一个的装饰上多个物件.

  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
  • 处理那些可以撤消的职责。
  • 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展.

优缺点

  • 装饰对象和真实对象有相同的接口。这样客户端对象就可以以和真实对象相同的方式和装饰对象交互。
  • 装饰对象包含一个真实对象的索引(reference)
  • 装饰对象接受所有的来自客户端的请求。它把这些请求转发给真实的对象。
  • 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

优点

  • 比静态继承更灵活
  • 避免在层次结构高层的类有太多的特征
  • 装饰类和被装饰类可以独立发展,不会相互耦合

缺点

多层装饰比较复杂。

经典实现

框架中的实现

i/o系统中的inputStream

1335887-20190525154810267-1646308742

InputStream作为抽象构件,其下面大约有如下几种具体基础构件,从不同的数据源产生输入:

  • ByteArrayInputStream,从字节数组产生输入;
  • FileInputStream,从文件产生输入;
  • StringBufferInputStream,从String对象产生输入;
  • PipedInputStream,从管道产生输入;
  • SequenceInputStream,可将其他流收集合并到一个流内;

  FilterInputStream作为装饰器在JDK中是一个普通类,其下面有多个具体装饰器比如BufferedInputStream、DataInputStream等。我们以BufferedInputStream为例,使用它就是避免每次读取时都进行实际的写操作,起着缓冲作用。

0%