设计模式之jdk动态代理模式、责任链模式-java实现

设计模式之JDK动态代理模式、责任链模式

需求场景

  • 当我们的代码中的类随着业务量的增大而不断增大仿佛没有尽头时,我们可以考虑使用动态代理设计模式,代理类的代码量被固定下来,不会随着业务量的增大而增大。
  • 当我们想要在类方法调用前、调用后等自动插入一些额外的功能时,可以考虑使用动态代理来实现而不用修改类的源代码。
  • 动态代理对象是动态生成的,不是定义好的,所以动态代理模式可以作为一种解除耦合的手段。
  • 动态代理模式也可以作为责任链设计模式的实现手段。

前提条件

JDK动态代理的被代理对象是需要实现接口的。

成熟案例

Spring框架的AOP编程,就是使用动态代理实现的。

手写案例

首先,我们的被代理对象要实现一个公共的接口,这样可以做到一个大类型的整体代理,下面是这个接口及其实现类。

public interface IMyClass{
    public void saySomething(String msg);
}
public class MyClassImpl implements IMyClass{
    @Override
    public void saySomething(String msg){
        System.out.println(msg);
    }
}

现在我们想要使用代理对象来代理这个类,但是代理对象从哪里来呢?所以,我们需要写一个动态产生代理对象的“工厂”。这个“工厂”需要实现一个叫做 InvocationHandler 的接口。

public class MyProxy<T> implements InvocationHandler {
    //实际对象,即被代理对象
    private T target;
    //绑定方法,获取代理对象
    public T bind(T target) {
        this.target = target;
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用方法前做的事");
        //调用方法
        Object result = method.invoke(target, args);
        System.out.println("调用方法后做的事");
        return result;
    }
}

现在我们有了被代理对象,有了代理对象的生产“工厂”,就可以开始试一试了。

public class Test{
    public static void main(String[] args){
        //获取代理对象
        IMyClass myClassProxy = new MyProxy<IMyClass>().bind(new MyClassImpl());
        myClassProxy.saySomething("Hello World!");
    }
}

结果如下:

调用方法前做的事

Hello World!

调用方法后做的事

模拟拦截器

使用jdk代理模式很容易实现一个拦截器,下面是我们的拦截器的接口和一个实现类。

public interface Interceptor{
    public boolean before(Object proxy, Method method, Object[] args, Object target) throws Exception;
    public Object around(Object proxy, Method method, Object[] args, Object target) throws Exception;
    public void after(Object proxy, Method method, Object[] args, Object target) throws Exception;
}
public class InterceptorImpl implements Interceptor{
    @Override
    public boolean before(Object proxy, Method method, Object[] args, Object target) throws Exception{
        System.out.println("Before!");
        if(((String)args[0]).length() <= 10){
            //未通过验证
            System.out.println("It's too short!");
            return false;
        }
        //通过验证
        return true;
    }
    
    @Override
    public Object around(Object proxy, Method method, Object[] args, Object target) throws Exception{
        System.out.println("add something satrt!");
        args[0] += " world!";
        Object result = method.invoke(target, args);
        System.out.println("add something end!");
        return result;
    }
    
    @Override
    public void after(Object proxy, Method method, Object[] args, Object target) throws Exception{
        System.out.println("After!");
    }
}

将我们的代理类生产“工厂”稍作修改

public class MyProxy<T> implements InvocationHandler {
    //实际对象,即被代理对象
    private T target;
    //我们的拦截器类名
    private String interceptorName;
    //绑定方法,获取代理对象
    public T bind(T target, String interceptorName) {
        this.target = target;
        this.interceptorName = interceptorName;
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(null == this.interceptorName){
            return method.invoke(target, args);
        }
        Object result = null;
        Interceptor interceptor = (Interceptor)Class.forName(this.interceptorName).newInstance();
        if(interceptor.before(proxy, method, args, target)){
            result = method.invoke(target, args);
        }else{
            result = interceptor.around(proxy, method, args, target);
        }
        interceptor.after(proxy, method, args, target);
        return result;
    }
}

试一试我们的拦截器

public class Test {
    public static void main(String[] args) {
        IMyClass myClassProxy = new MyProxy<IMyClass>().bind(new MyClassImpl(), "com.test.InterceptorImpl");
        myClassProxy.saySomething("hello");
        System.out.println("***************************************");
        myClassProxy.saySomething("123456789012");
    }
}

结果如下:

Before!

It's too short!

add something satrt!

hello world!

add something end!

After!


Before!

123456789012

After!

可以看到,我们成功实现了拦截的功能,增强了方法。

进阶责任链模式

责任链模式可以基于Jdk动态代理实现,模拟一下多个拦截器对同一个对象的拦截,你可以想象成一个员工要请假,把请假条先交给小组长签字,然后给项目经理签字,再返回给小组长,再到自己手上的场景。这个被代理的对象就是这个请假条,这些拦截器就是小组长和项目经理。

首先,我们再实现一个项目经理,把“小组长”的代码稍稍改一下即可。

public class InterceptorImpl1 implements Interceptor{
    @Override
    public boolean before(Object proxy, Method method, Object[] args, Object target) throws Exception{
        System.out.println("Before1!");
        if(((String)args[0]).length() <= 10){
            //未通过验证
            System.out.println("It's too short1!");
            return false;
        }
        //通过验证
        return true;
    }
    
    @Override
    public Object around(Object proxy, Method method, Object[] args, Object target) throws Exception{
        System.out.println("add something satrt1!");
        args[0] += " world1!";
        Object result = method.invoke(target, args);
        System.out.println("add something end1!");
        return result;
    }
    
    @Override
    public void after(Object proxy, Method method, Object[] args, Object target) throws Exception{
        System.out.println("After1!");
    }
}

下面开始“递交请假条”。

public class Test {
    public static void main(String[] args) {
        IMyClass myClassProxy = new MyProxy<IMyClass>().bind(new MyClassImpl(), "com.test.InterceptorImpl");
        IMyClass myClassProxy1 = new MyProxy<IMyClass>().bind(myClassProxy, "com.test.InterceptorImpl1");
        myClassProxy1.saySomething("hello");
        System.out.println("***************************************");
        myClassProxy1.saySomething("123456789012");
    }
}

结果如下

Before1! 

It's too short1!

add something satrt1!

Before!

hello world1!

After!

add something end1!

After1!


Before1!

Before!

123456789012

After!

After1!

看,是不是外面又套了一层?这个想不想是Spring的AOP编程的效果呢?其实原理就是这样!

总结

动态代理模式是一种非常重要的设计模式。我们可以看到,很多的框架都大量使用动态代理模式来实现其特殊的功能,这个设计模式需要好好好掌握。

责任链设计模式可以看作是一种扩展,仔细体会一下就能够领会其中的奥妙。大家可以仔细看看责任链模式案例运行结果的顺序,有助于理解哦!

开发模式是前任对某一类相似问题的解决方案进行的总结,我们可以从中吸取经验,但也不能盲目使用,也不能为了使用设计模式而使用设计模式。作为一个coder,要始终保持自己活跃的思维,不能将思维局限在一个设计模式上。开发熟练度在一定程度上决定了你的工作效率,但是思维的活跃度和发散性决定了你的天花板,也在很大程度上决定了你的工作效率。

你虽然在为别人工作,但是,你也在创造自己的世界!

猜你喜欢

转载自www.cnblogs.com/NepNeptune/p/10707523.html