設計模式——代理設計模型

在Spring中的相關介紹 https://blog.csdn.net/m0_37989980/article/details/104593905

具體什麼是靜態代理、動態代理這裏不贅述, 可以參考上面 !

一、靜態代理

/**
 * Description: 傳統靜態代理的舉例
 * <p>
 * 特點: 代理類和被代理類在編譯期間, 就確定下來了
 *
 * @author zygui
 * @date Created on 2020/6/18 15:12
 */
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 proxy = new ProxyClothFactory(nike);

        // 代理類執行的工作,實際是被代理類乾的事情
        proxy.produceCloth();
    }
}

二、動態代理

想要實現動態代理, 需要解決的問題?

  • 問題一: 如何根據加載到內存中被代理類, 動態的創建一個代理類及其對象
  • 問題二: 當通過代理類的對象調用方法時, 如何動態的去調用被代理類中的同名方法
/**
 * Description: 動態代理的舉例
 *
 *      代理類和被代理類要實現同一接口!
 *
 * @author zygui
 * @date Created on 2020/6/18 15:39
 */

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 ProxyFactory {

    /**
     * 調用此方法,通過傳遞過來的被代理類對象, 返回一個該被代理類對象的代理對象; 解決問題一
     *
     * @param obj 被代理類的對象
     * @return
     */
    public static Object getProxyInstance(Object obj) {

        /*
            // 用來創建代理類的方法
            public static Object newProxyInstance(
                  ClassLoader loader,      // 和被代理類使用同一加載器
                  Class<?>[] interfaces,   // 因爲代理類和被代理類要實現同一接口, 這裏獲取被代理類所實現的接口, 供創建出來的代理類也實現這些接口
                  InvocationHandler h      // 解決上面的問題二: 會去找下面的Invoke方法
            )

            也就是說, 創建的代理類對象去調用a方法時, 被代理類就會去handler裏面調用invoke方法
         */
        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(), 在invoke方法中的參數Method就是代理類對象調用的方法對象
    // 將被代理類要執行的方法a的功能就聲明在invoke()中了
    @Override
    /*
        參數:
            Object proxy    :   代理類對象
            Method method   :   代理類調用的那個方法,這裏就是該方法
            Object[] args   :   代理類調用的那個方法中的參數
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // method: 即爲 代理類對象調用的方法, 此方法也就作爲了 被代理類對象 要調用的方法
        // 下面的invoke方法中的 參數1: 調用該方法的對象(這裏就是被代理類的對象), 參數2: 是調用該方法的參數
        Object retrunValue = method.invoke(obj, args);
        return retrunValue;
    }
}

public class DynamicProxyTest {
    public static void main(String[] args) {

        // 被代理類對象
        SuperMan superMan = new SuperMan();

        // proxyInstance代理類對象(此時是superMan的代理對象)
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);

        // 通過代理類對象調用下面的方法, 就動態調用了被代理類中的同名方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣燙");

    }
}

此時通過調用代理類中的方法, 就動態的調用的是被代理類中的同名方法了!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章