Java设计模式(一)代理模式学习

Java代理模式学习

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法


无代理模式的代码

比如说这里有一个接口Hello

public interface Hello{
    void say(String name);
}

别人基于这个接口实现了它的方法

public class HelloImpl implements Hello{
    @Override
    public void say(String name){
        System.out.println("Hello " + name);
    }
}

突然有一天要求你要在println方法的前后处理一些逻辑,怎么做呢?可能最直接的方法就是把这些逻辑直接写在say()里面了,比如

public class HelloImpl implements Hello{
    @Override
    public void say(String name){
        before();
        System.out.println("Hello! " + name);
        after();
    }
    private void before(){
        System.out.println("before");
    }
    private void after(){
        System.out.println("after");
    }
}

但是这样直接修改别人代码的方式肯定不够优雅,这样可以通过代理的方式来扩展该方法。


静态代理

现在写一个HelloProxy类,让它去调用HelloImpl的say()方法,在调用前后分别进行逻辑处理不就可以了吗

public class HelloProxy implements Hello{
    private Hello hello;
    public HelloProxy(){
        hello = new HelloImpl();
    }
    @Override
    public void say(String name){
        before();
        System.out.println("Hello! " + name);
        after();
    }
    private void before(){
        System.out.println("before");
    }
    private void after(){
        System.out.println("after");
    }
}

写一个main方法测试一下

public static void main(String[] args){
    Hello helloProxy = new HelloProxy(); 
    helloProxy.say("Jack");
}

运行一下结果为

before
Hello! Jack
after

原来HelloProxy就是所谓的“代理模式”,但这仅仅是最初级的代理模式,一旦接口增加方法,目标对象与代理对象都要维护


JDK动态代理

动态代理有以下特点:

  1. 代理对象,不需要实现接口
  2. 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
  3. 动态代理也叫做:JDK代理,接口代理
public class DynamicProxy implements InvocationHandler{
    private Object target;
    public DynamicProxy(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws
    Throwable{
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    } 
    private void before(){
        System.out.println("before");
    }
    private void after(){
        System.out.println("after");
    }
}

DynamicProxy 类中,定义了一个Object类型的target变量,他就是被代理的目标对象,通过构造函数来初始化(“注入”),DynamicProxy实现了InvocationHandler,它必须实现接口的invoke方法。

写一个mian方法看看实际使用:

public static void main(String[] args){
    Hello hello = new HelloImpl();
    DynamicProxy dynamicProxy = new DynamicProxy(hello);
    Hello helloProxy = (hello) Proxy.newProxyInstance(
        hello.getClass().getClassLoader(),
        hello.getClass().getInterfaces(),
        dynamicProxy
    );
    helloProxy.say("Jack");
}

打印结果和前面一样

before
Hello! Jack
after

但是Proxy.newProxyInstance这个写的感觉有点复杂了,于是重构一下DynamicProxy代码

public class DynamicProxy implements InvocationHandler{
    private Object target;
    public DynamicProxy(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws
    Throwable{
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    } 
    @SuppressWarnings("unchecked")
    public <T> T getProxy(){
        return (T) Proxy.Proxy.newProxyInstance(
            target .getClass().getClassLoader(),
            target .getClass().getInterfaces(),
            this
        );
    }
    private void before(){
        System.out.println("before");
    }
    private void after(){
        System.out.println("after");
    }
}

现在main方法可以写得简单一点了

public static void main(String[] args){
    Hello hello = new HelloImpl();
    DynamicProxy dynamicProxy = new DynamicProxy(hello);
    Hello helloProxy = dynamicProxy.getProxy();
    helloProxy.say("Jack");
}

CGlib动态代理

JDK动态代理并不是万能的,比如要代理一个没有任何接口的类,它就没有用武之地了,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理。比如Spring和Hibernate都用上了这种代理
有了上面的基础,实现它也不难

public class CGLibProxy implements MethodInterceptor{
    private static CGLibProxy instance = new CGLibProxy();//这里使用到了单例模式
    private CGLibProxy(){//限制外界去new CGLibProxy
    }
    public static CGLibProxy getInstance(){
        return instance;
    }
    public <T> T getProxy(Class<T> cls){
        return (T) Enhancer.create(cls, this);
    }
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        before();
        //执行目标对象的方法
        Object result = proxy.invokeSuper(obj, args);
        after();
        return result;
    }
    private void before(){
        System.out.println("before");
    }
    private void after(){
        System.out.println("after");
    }
}

现在main方法可以更简单了,当然结果也是一样的

public static void main(String[] args){
    Hello helloProxy = CGLibProxy.getInstance().getProxy(HelloImpl.class);
    helloProxy.say("Jack");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值