写点什么

设计模式【8】-- 手工耿教我写装饰器模式

作者:秦怀杂货店
  • 2022 年 1 月 06 日
  • 本文字数:1892 字

    阅读完需:约 6 分钟

装饰器模式

前面学习了好几种设计模式,今天继续...



装饰器模式,属于结构型模式,用来包裹封装现在的类对象,希望可以在不修改现在类对象和类定义的前提下,能够拓展对象的功能。


调用的时候,使用的是装饰后的对象,而不是原对象。,提供了额外的功能。


不知道大家有没有看手工耿的自制钢琴烤串车视频【https://www.bilibili.com/video/BV1334y1Z7kq?spm_id_from=333.999.0.0 】, 本来是一个钢琴,但是为了边弹琴,边烤串,改造装饰了一下,变成了特殊的钢琴,提供了额外的烤串功能。典型的装饰器模式



目的: 为了灵活的拓展类对象的功能。


主要包括以下几种角色:


  • 抽象组件(Component): 被装饰的原始类的抽象,可以是抽象类,亦或是接口。

  • 具体实现类(ConcreteComponent):具体的被抽象的类

  • 抽象装饰器(Decorator): 通用抽象器

  • 具体装饰器(ConcreteDecorator):Decorator 的具体实现类,理论上,每个 ConcreteDecorator都扩展了Component对象的一种功能。

优缺点

优点:


  • 相对于类继承,包裹对象更加容易拓展,更加灵活

  • 装饰类和被装饰类相互独立,耦合度比较低

  • 完全遵守开闭原则。


缺点:


  • 包裹对象层级较深的时候,理解难度较大。

实现

先抽闲一个乐器接口类 Instrument


public interface Instrument {    void play();}
复制代码


弄两种乐器PianoGuitar ,实现乐器接口:


public class Piano implements Instrument{    @Override    public void play() {        System.out.println("手工耿弹奏钢琴");    }}
复制代码


public class Guitar implements Instrument{    @Override    public void play() {        System.out.println("手工耿弹吉他");    }}
复制代码


不管手工耿要边弹吉他边烧烤,还是边弹钢琴边烧烤,还是边弹钢琴边洗澡,不管什么需求,我们抽象一个装饰器类,专门对乐器类进行包装,装饰。


public class InstrumentDecorator implements Instrument{    protected Instrument instrument;
public InstrumentDecorator(Instrument instrument) { this.instrument = instrument; }
@Override public void play() { instrument.play(); }}
复制代码


上面的是抽象的装饰类,具体装饰成什么样,我们得搞点实际动作,那就搞个烧烤功能。


public class BarbecueInstrumentDecorator extends InstrumentDecorator {    public BarbecueInstrumentDecorator(Instrument instrument) {        super(instrument);    }
@Override public void play() { instrument.play(); barbecue(); }
public void barbecue(){ System.out.println("手工耿在烧烤"); }}
复制代码


测试一下:


public class DecoratorDemo {    public static void main(String[] args) {        Instrument instrument = new Piano();        instrument.play();        System.out.println("----------------------------------------");        InstrumentDecorator barbecuePiano = new BarbecueInstrumentDecorator(new Piano());        barbecuePiano.play();        System.out.println("----------------------------------------");        InstrumentDecorator barbecueGuitar = new BarbecueInstrumentDecorator(new Guitar());        barbecueGuitar.play();    }}
复制代码


测试结果如下,可以看到不装饰的时候,只能干一件事,装饰之后的对象,既可以弹奏乐器,也可以烧烤,不禁感叹:原来手工耿是设计模式高手:


手工耿弹奏钢琴----------------------------------------手工耿弹奏钢琴手工耿在烧烤----------------------------------------手工耿弹吉他手工耿在烧烤
复制代码

小结一下

设计模式,不是银弹,只是在软件工程或者说编程中,演变出来的较好实践。我们不能为了设计模式而设计模式,学习理论只是为了更好的使用它,知道什么时候应该使用,什么时候不该使用。


装饰器模式是为了拓展其功能,但又不破坏原来的结构的前提下做的,其实在Java IO的源码里面有大量使用,比如:


DataInputStream dis = new DataInputStream(                    new BufferedInputStream(                            new FileInputStream("test.txt")                            )                    );
复制代码


先把FileInputStream传递给BufferedInputStream弄成一个装饰对象,再把装饰对象传递给DataInputStream,再装饰一遍。最终,FileInputStream 被包装成了 DataInputStream,感兴趣的同学可以翻一下源码。



【作者简介】


秦怀,公众号【秦怀杂货店】作者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。


剑指Offer全部题解PDF


开源编程笔记

发布于: 刚刚
用户头像

纵使缓慢,驰而不息。 2018.05.17 加入

慢慢走,比较快。公众号:秦怀杂货店

评论

发布
暂无评论
设计模式【8】-- 手工耿教我写装饰器模式