原文链接:https://www.leahy.club/archives/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E4%BB%A3%E7%90%86%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F

什么是***?

***就是为其他对象提供一些***服务以控制的访问或者扩展功能。

Java中常见的***模式主要有两种:一种是静态***,一种是动态***。

静态***:

静态***就是***类和被***类都实现了相同的接口,在使用时将被***类作为参数传给***类,在***类中调用被***类的方法,并且在这些方法调用时可以加入一些方法,比如权限控制等,从而实现某些特定的功能。但是静态***的缺点在于必须有一个***类实现了被***类的接口,这样会导致两个局限:①如果同时***多各类,会导致***类的无限扩展②如果被***类中有多个方法,同样的逻辑需要反复实现。

动态***:

为了解决静态***的不足,提出了动态***。动态***在代码中并不会针对每个被***类实现其接口,而是根据被***类动态的生成***类。例如在Java中主要是使用反射包下的Proxy类和InvocationHandler接口来实现动态***。Proxy用来生成***对象;InvocationHandler主要用于自定义***逻辑处理;为了完成被***对象的方法拦截,需要在InvocationHandler对象中传入被***对象的实例。这样做的好处在于只要你在newProxyInstance方法中指定***需要实现的接口(需要用到反射),指定用于自定义处理的InvocationHandler对象,整个***的逻辑处理都在你自定义的InvocationHandler实现类中进行处理。至此,而我们终于可以从不断地写***类用于实现自定义逻辑的重复工作中解放出来了,从此需要做什么,交给InvocationHandler。

动态***的作用?

动态***可以在我们不改变源码的情况下,直接在方法中插入自定义的逻辑,这种编程方式叫做AOP,即面向切面编程。基于这样一种动态***,可以做很多事情,比如:事物的提交或回退、权限管理(***的设计)等。

静态***举例:

interface ClothFactory{

    void produceCloth();

}

//***类
class ProxyClothFactory implements ClothFactory{

    private ClothFactory factory;//用被***类对象进行实例化

    public ProxyClothFactory(ClothFactory factory){
        this.factory = factory;
    }

    @Override
    public void produceCloth() {
        System.out.println("***工厂做一些准备工作");

        factory.produceCloth();

        System.out.println("***工厂做一些后续的收尾工作");

    }
}

//被***类
class NikeClothFactory implements ClothFactory{

    @Override
    public void produceCloth() {
        System.out.println("Nike工厂生产一批运动服");
    }
}

public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被***类的对象
        ClothFactory nike = new NikeClothFactory();
        //创建***类的对象
        ClothFactory proxyClothFactory = new ProxyClothFactory(nike);

        proxyClothFactory.produceCloth();

    }
}

动态***举例:

interface Human {
    String getBelief();
    void eat(String food);
}

//被***类
class SuperMan implements Human {
    @Override
    public String getBelief() {
        return "I believe I can fly.";
    }
    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    } 
}
class HumanUtil{

    public void method1(){
        System.out.println("====================通用方法一====================");

    }

    public void method2(){
        System.out.println("====================通用方法二====================");
    }

}

/* 要想实现动态***,需要解决的问题? 问题一:如何根据加载到内存中的被***类,动态的创建一个***类及其对象。 问题二:当通过***类的对象调用方法a时,如何动态的去调用被***类中的同名方法a。 */

class ProxyFactory{
    //调用此方法,返回一个***类的对象。解决问题一
    public static Object getProxyInstance(Object obj){//obj:被***类的对象
        MyInvocationHandler handler = new MyInvocationHandler();

        handler.bind(obj);

        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }

}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;//需要使用被***类的对象进行赋值

    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过***类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
    //将被***类要执行的方法a的功能就声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        HumanUtil util = new HumanUtil();
        util.method1();

        //method:即为***类对象调用的方法,此方法也就作为了被***类对象要调用的方法
        //obj:被***类的对象
        Object returnValue = method.invoke(obj,args);

        util.method2();

        //上述方法的返回值就作为当前类中的invoke()的返回值。
        return returnValue;

    }
}

public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:***类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        //当通过***类对象调用方法时,会自动的调用被***类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣烫");

        System.out.println("*****************************");

        NikeClothFactory nikeClothFactory = new NikeClothFactory();

        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);

        proxyClothFactory.produceCloth();

    }
}