设计模式之装饰者模式
Posted Tonbby
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之装饰者模式相关的知识,希望对你有一定的参考价值。
对一个方法进行增强有三种方式:
1.继承
2.装饰者模式(静态代理)
3.动态代理(cglib)
由于自定义jdbc连接池中会用到装饰者模式,在这里,我们先来介绍装饰者模式。
定义:在不必改变原类文件和原类使用的继承情况下,动态的扩展一个对象的功能。
操作:它是通过创建一个包装对象,也就是用装饰来包裹真实的对象来实现的。
使用步骤:1.装饰者和被装饰者使用同一个接口或继承同一个类。(这样比较方便重写里面的方法)
2.装饰者中要有被装饰者的引用 。(这样才能在装饰者的方法中对被装饰者进行增强,并且引用时可以提供一个构造方法,把被装饰者传入装饰者的构造方法中)
3.对需要增强的方法进行增强。
4.对不需要增强的方法调用原来的方法。(这里可以采用适配器模式,避免重写多个不需要重写的方法)
拿车来举例子
QQ车是一个普通的车,具有跑和停两个方法。
public class QQ { public void run(){ System.out.println("跑"); } public void stop(){ System.out.println("停"); } }
目标:使用装饰者类,对QQ车进行增强,让它变成QQ飞车跑 和急刹车停。
首先需要定义一个接口或者父类,让它具有跑和停的方法,让装饰者类和被装饰者类继承它,这样方便对方法进行重写增强。
public class Car { public void run(){} public void stop(){} }
被装饰类继承父类:
public class QQ extends Car{ public void run(){ System.out.println("跑"); } public void stop(){ System.out.println("停"); } }
装饰类:
public class FlyCar extends Car{ private QQ qq; public FlyCar() { //因为下面提供了有参的构造方法,所以必须重写无参的构造方法 } public FlyCar(QQ qq){ //提供了有参的构造方法,把被装饰者传入装饰者类中 this.qq = qq; } @Override public void run() { System.out.print("fly car "); //对方法进行增强 qq.run(); } @Override public void stop() { System.out.print("急刹车 "); //对方法进行增强 qq.stop(); } }
测试代码:
public class Test { public static void main(String[] args) { QQ qq = new QQ(); qq.run(); qq.stop(); System.out.println("被装饰后:运行结果-----"); FlyCar f = new FlyCar(new QQ()); f.run(); f.stop(); } }
运行结果:
跑 停 被装饰后:运行结果----- fly car 跑 急刹车 停
这个例子可以看到:没有改变原来的QQ类,同时也没有定义QQ类的子类来实现扩展。
优点:
使用装饰者模式比使用继承更加灵活,因为是一个动态的方式扩展一个对象的功能,在运行时可以选择不同的装饰器,从而实现不同的行为,
通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。
低耦合。具体装饰类和具体被装饰类可以独立变化,可以根据需要来增加具体的装饰类和被装饰类,使用时进行组合,原有代码无需改变。符合“开闭原则”。
六大设计原则之开闭原则:对扩展开放,对修改关闭
缺点:
会产生很多小对象,增加系统的复杂性
排错比较困难,对于多次装饰的对象,寻找错误需要逐级排查,不方便。
在自定义jdbc连接池中,我们需要对connection的close()方法进行装饰,让它的close()方法归还连接,而不是直接销毁连接。
使用场景:
需要扩展一个类的功能,或给一个类添加附加指责。
动态的给一个对象添加功能,不用可以随时动态的撤销掉。
需要增加由一些基本功能的排列组合而产生的非常大量的功能,使用继承不太现实
类定义被隐藏或类定义不能生成子类时。
以上是关于设计模式之装饰者模式的主要内容,如果未能解决你的问题,请参考以下文章