1. 程式人生 > >Android設計模式之代理模式

Android設計模式之代理模式

代理模式(Proxy Pattern)也稱為委託模式。

代理模式的定義

為其它物件提供一種代理以控制對這個物件的訪問。

代理模式的使用場景

當無法或者不想直接訪問某個物件或者訪問某個物件存在困難時,可以通過一個代理物件來間接訪問,為了保證客戶端使用的透明性,委託物件與代理物件需要實現相同的介面。

代理模式的UML類圖

 

 

角色介紹:

Subject:抽象主題類

該類的主要職責是宣告真實主題與代理的共同介面方法,該類既可以是一個抽象類也可以是一個介面。

RealSubject:真實主題類

該類也被稱為被委託類或被代理類,該類定義了代理所表示的真實物件,由其執行具體的業務邏輯方法,而客戶端則通過代理類間接呼叫真實主題類中定義的方法。

ProxySubject:代理類

該類也稱為委託類或代理類,該類持有一個對真實主題類的引用,在其所實現的介面方法中呼叫真實主題類中相應的介面方法執行,以此起到代理的作用。

代理模式大概分為兩部分:一是靜態代理,二是動態代理;靜態代理程式碼如Demo所示,代理者的程式碼由程式設計師自己或者通過一些自動化工具生成固定的程式碼再對其進行編譯,也就是在我們的程式碼執行前 代理類的 class編譯檔案 就已經存在。

而動態代理和靜態代理相反,通過反射機制 動態生成代理者的物件,也就是說我們在code階段不需要知道代理誰,代理誰將會在執行階段決定。而Java給我們提供了一個便捷的動態代理介面InvocationHandler,實現該介面需要重寫其呼叫方法invoke。

public class DynamicProxy implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return null;
    }
}

在這裡,通過invoke方法呼叫具體的被代理方法,也就是真實的方法。

public class DynamicProxy implements InvocationHandler {

    private Object object;

    public DynamicProxy(Object object) {
        this.object = object;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        //呼叫被代理物件的方法
        Object result = method.invoke(object, args);
        return result;
    }
}

 

動態代理通過一個代理類來代理n個被代理類,其實質是對代理者與被代理者進行解耦,使兩者沒有直接的耦合關係。相對而言靜態代理則只能給定介面下的實現類做代理,如果介面不同則需要重新定義不同的代理類,較為複雜。但是靜態代理更加符合面向物件原則。

靜態代理和動態代理是從Code方面區分代理模式的兩種方式,我們也可以從其適用範圍來區分不同型別的代理模式。

1.遠端代理(Remote Proxy):為某個物件在不同的記憶體地址空間 提供區域性代理。使系統可以將Server部分的實現隱藏,以便Client可以不必考慮Server的存在。

2.虛擬代理(Virtual Proxy):使用一個代理物件表示一個十分耗資源的物件並在正真需要的時候才建立。

3.保護代理(Production Proxy):使用代理控制對原始物件的訪問。該型別的代理常被用於原始物件有不同訪問許可權的情況。

4.智慧引用(Smart Reference):在訪問原始物件時執行一些自己的附加操作並對指向原始物件的引用計數。

需要注意的是,靜態和動態代理都可以應用於上述4鍾情形。

 

代理模式簡單Demo

D:\Users\user\AndroidStudioProjects\ProxyPatternDemo\app\src\main\java\proxy_pattern\gome\com\proxypatterndemo\Subject.java

public abstract class Subject {

    public abstract void visit();
}


D:\Users\user\AndroidStudioProjects\ProxyPatternDemo\app\src\main\java\proxy_pattern\gome\com\proxypatterndemo\RealSubject.java

public class RealSubject extends Subject {
    @Override
    public void visit() {
        Log.v(TAG, "Real subject!");
    }
}

D:\Users\user\AndroidStudioProjects\ProxyPatternDemo\app\src\main\java\proxy_pattern\gome\com\proxypatterndemo\ProxySubject.java


public class ProxySubject extends Subject {
    private RealSubject mSubject;//持有真實主題的引用

    public ProxySubject(RealSubject subject) {
        this.mSubject = subject;
    }

    @Override
    public void visit() {
        //通過真實主題引用的物件呼叫真實主題中的邏輯方法
        mSubject.visit();
    }
}


D:\Users\user\AndroidStudioProjects\ProxyPatternDemo\app\src\main\java\proxy_pattern\gome\com\proxypatterndemo\MainActivity.java

public class MainActivity extends AppCompatActivity {

    public static final String TAG = "ZY_PROXY_PATTERN";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //構造一個真實主題物件
        RealSubject real = new RealSubject();
        //通過真實主題物件構建一個代理物件
        ProxySubject proxy = new ProxySubject(real);

        //呼叫代理的相關方法
        proxy.visit();
    }
}

 

Log分析:

V/ZY_PROXY_PATTERN: Real subject!

 

在java的動態代理機制中,有兩個重要的類或介面,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和介面是實現我們動態代理所必須用到的。

首先我們先來看看java的API幫助文件是怎麼樣對這兩個類進行描述的:

 

每一個動態代理類都必須要實現InvocationHandler這個介面,並且每個代理類的例項都關聯到了一個handler,當我們通過代理物件呼叫一個方法的時候,這個方法的呼叫就會被轉發為由InvocationHandler這個介面的 invoke 方法來進行呼叫。我們來看看InvocationHandler這個介面的唯一一個方法 invoke 方法:

 

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

 

我們看到這個方法一共接受三個引數,那麼這三個引數分別代表什麼呢?

 

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

 

proxy:  指代我們所代理的那個真實物件

method:  指代的是我們所要呼叫真實物件的某個方法的Method物件

args:  指代的是呼叫真實物件某個方法時接受的引數

 

Android原始碼中代理模式實現

 

WindowManager只是一個代理,實際的管理功能是通過WindowManagerGlobal實現的。

Android原始碼中代理模式的實現,比如原始碼裡面的ActivityManagerProxy代理類,其具體代理的是ActivityManagerNative的子類ActivityManagerService,ActivityManagerService在本書中其他章節略有介紹,這裡不再多說,主要來看看ActivityManagerProxy這個類。

上面的IActivityManager這個介面類就相當於代理模式中的抽象主題,真正實現主題的是ActivityManagerService類。

 

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
        ... ...
}


@SystemService(Context.ACTIVITY_SERVICE)
public class ActivityManager {

}

以ActivityManager的getAppTasks為例:


 /**
     * Get the list of tasks associated with the calling application.
     *
     * @return The list of tasks associated with the application making this call.
     * @throws SecurityException
     */
    public List<ActivityManager.AppTask> getAppTasks() {
        ArrayList<AppTask> tasks = new ArrayList<AppTask>();
        List<IBinder> appTasks;
        try {
            appTasks = getService().getAppTasks(mContext.getPackageName());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
        int numAppTasks = appTasks.size();
        for (int i = 0; i < numAppTasks; i++) {
            tasks.add(new AppTask(IAppTask.Stub.asInterface(appTasks.get(i))));
        }
        return tasks;
    }


  /**
     * @hide
     */
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

//Android framework中大多使用靜態內部類的方式實現單例。
private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };





package android.util;

/**
 * Singleton helper class for lazily initialization.
 *
用於延遲初始化的Singleton helper類。
 * Modeled after frameworks/base/include/utils/Singleton.h
 *
 * @hide
 */
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

通過上述程式碼可以發現:只是簡單呼叫了ActivityManager 的 getService() 方法獲取到一個IActivityManager型別的物件。然後通過該物件再呼叫其getAppTasks 方法。注意,這裡結合代理模式理解。而ActivityManager 的getService()方法只是單純的返回了。

getService()方法的操作是什麼呢?

 public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }


private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);("activity" -> Context.ACTIVITY_SERVICE)
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

上述程式碼通過靜態內部類的方式構建了一個Singleton<IActivityManager> 型別的IActivityManagerSingleton 物件, 其中通過ServiceManager.getService(Context.ACTIVITY_SERVICE)方法獲取一個系統級的Service,而這個Service實質上就是ActivityManagerService,這裡也就完成了建立了一個ActivityManagerService的Client代理物件IActivityManager例項

 

#ActivityManagerService
 @Override
    public List<IBinder> getAppTasks(String callingPackage) {
        int callingUid = Binder.getCallingUid();
        long ident = Binder.clearCallingIdentity();

        synchronized(this) {
            ArrayList<IBinder> list = new ArrayList<IBinder>();
            try {
                if (DEBUG_ALL) Slog.v(TAG, "getAppTasks");

                final int N = mRecentTasks.size();
                for (int i = 0; i < N; i++) {
                    TaskRecord tr = mRecentTasks.get(i);
                    // Skip tasks that do not match the caller.  We don't need to verify
                    // callingPackage, because we are also limiting to callingUid and know
                    // that will limit to the correct security sandbox.
                    if (tr.effectiveUid != callingUid) {
                        continue;
                    }
                    Intent intent = tr.getBaseIntent();
                    if (intent == null ||
                            !callingPackage.equals(intent.getComponent().getPackageName())) {
                        continue;
                    }
                    ActivityManager.RecentTaskInfo taskInfo =
                            createRecentTaskInfoFromTaskRecord(tr);
                    AppTaskImpl taskImpl = new AppTaskImpl(taskInfo.persistentId, callingUid);
                    list.add(taskImpl.asBinder());
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
            return list;
        }
    }

 

 

 

 

 

參考《Android原始碼設計模式》