设计模式之装饰者模式

对一个方法进行增强有三种方式:

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()方法归还连接,而不是直接销毁连接。

使用场景:

需要扩展一个类的功能,或给一个类添加附加指责。

动态的给一个对象添加功能,不用可以随时动态的撤销掉。

需要增加由一些基本功能的排列组合而产生的非常大量的功能,使用继承不太现实

类定义被隐藏或类定义不能生成子类时。

 

posted @ 2018-05-13 11:42  tonbby  阅读(165)  评论(0编辑  收藏  举报