設計模式—代理

代理模式UML

圖1-1,代理模式UML建模

什么是代理模式?

給某個對象提供一個代理對象,并由代理對象控制對于原對象的訪問,即客戶不直接操控原對象,而是通過代理對象間接地操控原對象。

比如說,我想在喝星巴克的咖啡;正常流程下,我要自己去星巴克店里購買,是我執行買這個操作,但現在我通過外賣服務,這個買的人就變成了外賣小哥,而不是我本人,這里的外賣小哥其實就是我的代理,他代我實現了這個買的操作。這里的我相當于Client,買咖啡是一個借口Subject,外賣小哥就是ReallySubject,ProxySubject就是我要買咖啡的一個代理(我并不關心真正的執行者是誰)

一個簡單的代理實現代碼

public class Delegate {
    public void main() {
        // 真正執行者
        Subject reallySubject =new ReallySubject();
        // 代理執行者
        Subject proxySubject =new ProxySubject(reallySubject);
        // 看似是代理執行者在做事【所謂的代理】
        proxySubject.doSomethings();
    }
}
interface Subject {
    void doSomethings();
}
public class ReallySubjectimplements Subject {
    @Override
    public void doSomethings() {
        Log.e("實際執行人","真正要做事的");
    }
}
public class ProxySubjectimplements Subject {
    private Subjectsubject;
    public ProxySubject(Subject subject) {
        this.subject = subject;
    }
    @Override
    public void doSomethings() {
        Log.e("我是代辦人","通知真正辦事的者,辦事!");
        if (subject !=null)
            subject.doSomethings();
    }
}

什么是靜態代理和動態代理?

靜態代理:在編譯時就將接口、實現類、代理類實現了,說白點就是咱們自己手動全部敲出來。

動態代理:在程序運行時,根據需要動態的創建代理類及相關實例。

都是代理又為什么要區分靜態代理和動態代理呢?
當我們遇到某個需求要實現大量的代理的時候,每一個都要手動去敲是一件很費時操作,而且大部分的代碼又都是重復的,這個時候就有大神就提出了動態代理的方案,來簡化這些沒有營養的操作了,即動態代理的出現。

動態代理的實現

public class DelegateSubject implements InvocationHandler {
    private Subject subject;

    public DelegateSubject(Subject subject) {
        this.subject = subject;
    }

    /**
     *
     * @param proxy 代理對象(表示哪個代理對象調用了method方法)
     * @param method 調用方法
     * @param args 調用方法參數
     * @return 代理實例調用具體的方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        // 添加自己的代碼1
        // 根據自己的需要甚至可以不調用method.invoke()方法
        object = method.invoke(subject, args);
        // 添加自己的代碼2
        return object;
    }

}
public class Delegate {

    public void main() {
        // 真正執行者
        ReallySubject reallySubject = new ReallySubject();
        // 代理執行器
        DelegateSubject delegateSubject = new DelegateSubject(reallySubject);
        // 構造動態代理
        // 第一個參數 真正執行者加載器
        // 第二個參數 真正執行者實現的接口
        // 第三個參數 代理執行器
        Subject subject = (Subject) Proxy.newProxyInstance(
                ReallySubject.class.getClassLoader(),
                ReallySubject.class.getInterfaces(),  // 或者 new Class<?>[] { Subject.class },
                delegateSubject);
        // 通過代理執行對象方法
        // 調用此方法執行 DelegateSubject的invoke()
        subject.doSomethings();
    }

}

看看retrofit是怎么使用動態代理

  public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();

          @Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
              throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            ServiceMethod<Object, Object> serviceMethod =
                (ServiceMethod<Object, Object>) loadServiceMethod(method);
            OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
            return serviceMethod.callAdapter.adapt(okHttpCall);
          }
        });
  }

看了retrofit的代碼你會不會產生疑問,retrofit只有接口沒并沒有具體的執行者啊!!!
還記得上面的這段代碼么?

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        // 添加自己的代碼1
        // 根據自己的需要甚至可以不調用method.invoke()方法
        object = method.invoke(subject, args);
        // 添加自己的代碼2
        return object;
    }

中提到過 “根據需要你甚至可以不調用method.invoke()”,沒錯retrofit就這么干的

ServiceMethod<Object, Object> serviceMethod =
     (ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);

這段代碼只要是使用OkHttp進行網絡請求,并將OkHttp的返回結果作為最終函數的返回結果。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容