(三)代理模式

引言:人们在开发过程中会碰到很多个模块使用相同的代码或者对原有模块代码进行拓展,即增强额外的功能操作,根据OCP原则,所以人们开始想办法解决。
下面介绍四种方式:

1、继承

编写一个共同的抽象父类,不同的类分别继承它。
Car.java

abstract public class Car {
    public void whoUsed(){
        String user = "张三";
        System.out.println(user+"使用汽车时间:"+new Date());
    }
    abstract public void Branch();
}

BMW.java

public class BMW extends Car {
    @Override
    public void Branch() {
        super.whoUsed();
        System.out.println("BMW");
    }
}

Benci.java

public class Benci extends Car {
    @Override
    public void Branch() {
        super.whoUsed();
        System.out.println("Benci");
    }
}

ProxyTest.java

System.out.println("-----------父类继承-----------");
        BMW bmw = new BMW();
        Benci benci = new Benci();
        bmw.Branch();
        benci.Branch();

运行结果

-----------父类继承-----------
张三使用汽车时间:Thu May 31 16:22:02 CST 2018
BMW
张三使用汽车时间:Thu May 31 16:22:02 CST 2018
Benci

继承的方式,被增强的对象和增强的内容都是固定的,为了让被增强的对象和内容是可变的,我们采用代理模式。

2、静态代理

IPerson.java

public interface IPerson {
    public void eat();
    public void sleep();

}

Person.java

public class Person implements IPerson {
    public void eat() {
        System.out.println("吃饭中");
    }

    public void sleep() {
        System.out.println("睡觉中");
    }
}

ProxyTest.java

System.out.println("-----------静态代理-----------");
        IPerson person = new Person();
        StaticPersonProxy proxy = new StaticPersonProxy(person);
        proxy.eat();
        proxy.sleep();

运行结果

-----------静态代理-----------
吃饭之前:Thu May 31 16:22:02 CST 2018
吃饭中
吃饭之后:Thu May 31 16:22:02 CST 2018
睡觉之前:Thu May 31 16:22:02 CST 2018
睡觉中
睡觉之后:Thu May 31 16:22:02 CST 2018

静态代理使用时,需要定义接口,被代理对象与代理对象一起实现相同的接口。静态代理虽然可以让对象和内容发生改变,但是需要写接口和静态代理类,假设要写50个接口就要写50个静态代理类。为此,程序员经过思考想出了动态代理的方式进行拓展。

3、动态代理

IPerson.java

public interface IPerson {
    public void eat();
    public void sleep();

}

Person.java

public class Person implements IPerson {
    public void eat() {
        System.out.println("吃饭中");
    }

    public void sleep() {
        System.out.println("睡觉中");
    }
}

DynaProxyFactory.java

public class DynaProxyFactory {
    private Object target;

    public DynaProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxy(){
        ClassLoader loader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler handler = (InvocationHandler)new DynaProxyHandle(target);
        return Proxy.newProxyInstance(loader,interfaces,handler);
    }
}

DynaProxyHandle.java

public class DynaProxyHandle implements InvocationHandler {
    private Object target;

    public DynaProxyHandle(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object o, Method method, Object[] args) throws Throwable {
        Object result = null;
        if (method.getName().equals("eat")){
            System.out.println("吃饭前:"+new Date());
            result = method.invoke(target,args);
            System.out.println("吃饭后:"+new Date());
        }
        if (method.getName().equals("sleep")){
            System.out.println("睡觉前:"+new Date());
            result = method.invoke(target,args);
            System.out.println("睡觉后:"+new Date());
        }

        return result;
    }
}

ProxyTest.java

System.out.println("-----------动态代理-----------");
IPerson dynaproxy = (IPerson)new DynaProxyFactory(person).getProxy();
dynaproxy.eat();
dynaproxy.sleep();

运行结果

-----------动态代理-----------
吃饭前:Thu May 31 16:22:02 CST 2018
吃饭中
吃饭后:Thu May 31 16:22:02 CST 2018
睡觉前:Thu May 31 16:22:02 CST 2018
睡觉中
睡觉后:Thu May 31 16:22:02 CST 2018

动态代理使用时,需要定义接口,被代理对象需要实现接口,但代理对象就不需要实现接口。假设要写50个接口就要写1或2个动态代理类(DynaProxyFactory.java、DynaProxyHandle.java),一共51/52个类文件(InvocationHandler可以通过内部匿名类实现)。为了继续减少编写文件个数,为此,程序员经过思考想出了Cglib代理的方式进行拓展。

4、Cglib代理

Apple.java

public class Apple {
    public void color(){
        System.out.println("red");
    }
}

Banana.java

public class Banana {
    public void whichSeasonFruit(){
        System.out.println("Banana");
    }
}

CglibProxyFactory.java

public class CglibProxyFactory implements org.springframework.cglib.proxy.MethodInterceptor {
    private Object target;

    public CglibProxyFactory(Object target) {
        this.target = target;
    }
    public Object getProxy(){
        //1.⼯具类
        Enhancer en = new Enhancer();
        //2.设置⽗类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建⼦类(代理对象)
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("张三操作时间:"+new Date());
        Object result = method.invoke(target,args);
        return result;
    }
}

ProxyTest.java

System.out.println("-----------Cglib代理-----------");
Apple apple = new Apple();
Banana banana = new Banana();
Apple appleProxy = (Apple)new CglibProxyFactory(apple).getProxy();
Banana bananaProxy = (Banana)new CglibProxyFactory(banana).getProxy();
appleProxy.color();
bananaProxy.whichSeasonFruit();

运行结果

-----------Cglib代理-----------
张三操作时间:Thu May 31 18:04:50 CST 2018
red
张三操作时间:Thu May 31 18:04:50 CST 2018
Banana

Cglib代理使用时,不需要定义接口,但代理对象和被代理对象都就不需要实现接口。假设无论多少个Bean就要写1代理类,一共1个类文件就可以根据OCP原则拓展原有模块功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值