装饰器模式之前学过几种设计模式,今天继续...装饰器模式,属于结构模式,用来包裹并对当前Class对象进行封装,希望在不修改当前类对象和类定义的情况下,扩展对象的功能。调用时,使用装饰对象代替原始对象,提供额外的功能。不知道大家有没有看过耿哥自制钢琴烤肉车的视频【https://www.bilibili.com/video...】,本来就是一架钢琴,改装装饰后可以弹奏钢琴在烤串的同时,变成了一种特殊的钢琴,提供了额外的串烧功能。典型装饰者模式的目的:灵活扩展类对象的功能。主要包括以下几个角色:抽象组件(Component):对要装饰的原始类的抽象,可以是抽象类,也可以是接口。具体实现类(ConcreteComponent):具体抽象类抽象装饰器(Decorator):通用抽象器具体装饰器(ConcreteDecorator):Decorator的具体实现类,理论上每个ConcreteDecorator都扩展了一个Component对象的Function类型。优缺点优点:与类继承相比,包装对象更容易扩展,更灵活,装饰类和被装饰类相互独立,耦合度比较低,完全遵守开闭原则。缺点:当封装对象层次较深时,难以理解。实现先取出一个乐器接口类Instrument:publicinterfaceInstrument{voidplay();}得到Piano和Guitar两种乐器,实现乐器接口:publicclassPianoimplementsInstrument{@Overridepublicvoidplay(){系统输出。println("用手弹钢琴");}}publicclassGuitarimplementsInstrument{@Overridepublicvoidplay(){System.out.println("用手弹吉他");}}弹吉他不管是手动烧烤,边弹钢琴边烧烤,还是边弹钢琴边洗澡,不管是什么需求,我们抽象出一个装饰器类来对乐器进行包装装饰。公共类InstrumentDecorator实现Instrument{protectedInstrumentinstrument;公共InstrumentDecorator(仪器仪表){this.instrument=instrument;}@Overridepublicvoidplay(){instrument.play();}}上面是一个抽象的装饰类,具体的装饰什么的,我们要做一些实际的操作,所以我们来设置一个烧烤功能。publicclassBarbecueInstrumentDecoratorextendsInstrumentDecorator{publicBarbecueInstrumentDecorator(仪器仪表){super(仪器);}@Overridepublicvoidplay(){instrument.play();烧烤();}publicvoidbarbecue(){System.out.println("手动烧烤");}}测试它:publicclassDecoratorDemo{publicstaticvoidmain(String[]args){Instrumentinstrument=newPiano();乐器.play();System.out.println("---------------------------------------");InstrumentDecoratorbarbecuePiano=newBarbecueInstrumentDecorator(newPiano());烧烤钢琴演奏();System.out.println("--------------------------------------");InstrumentDecoratorbarbecueGuitar=newBarbecueInstrumentDecorator(newGuitar());烧烤吉他.play();}}测试结果如下,可以看到在没有装饰的情况下只能做一件事,装饰之后可以演奏乐器或者烧烤,不禁感叹:原来manualgeng是设计模式大师:手工耿弹琴----------------------------------------手弹弹琴手扒------------------------------------------ManuallyplaytheguitarManuallyplaytheguitarManuallyplaytheguitarManuallyatthebarbecue总结设计模式,它不是灵丹妙药,而是在软件工程或编程中演化出来的更好的实践我们不能为了设计模式而设计模式,学习理论只是为了使用它更好,知道什么时候使用它,什么时候不使用它。装饰者模式就是在不破坏原有结构的情况下,扩展其功能。其实在JavaIO的源码中被广泛使用,如:DataInputStreamdis=newDataInputStream(newBufferedInputStream(newFileInputStream("test.txt")));先把FileInputStream传给BufferedInputStream做一个装饰对象,然后把装饰对象传给DataInputStream,再装饰一遍。最后将FileInputStream封装成了DataInputStream,有兴趣的同学可以查看源码。【作者简介】:公众号【秦淮杂货铺】作者秦淮,技术之路不是一时的,山高水长,纵使慢也不会停。剑指全题OfferPDF开源编程笔记
