当你想控制外界对某个类的对象的直接访问时,可以使用代理模式.
定义
为其他类提供一种代理以控制外界对这个类的对象的访问.
核心作用
通过代理,控制对对象的访问;
可以详细控制访问某个类的方法,在调用这个方法前做前置处理, 调用这个方法后做后置处理.
AOP(Aspect Oriented Programming)面向切面编程的核心实现机制.
经典的使用模式:
- 代理类和被代理类实现同一个接口, 实现同一套API.
- 外界通过调用代理类的方法, 间接调用被代理类的方法.
- 在代理类中持有一个被代理类对象的引用, 真正的实现都是通过被代理类实现的.
代码中的使用
pulltorefresh项目
public interface ILoadingLayout {
public void setLoadingDrawable(Drawable drawable);
}
//代理类
public class LoadingLayoutProxy implements ILoadingLayout {
private final HashSet<LoadingLayout> mLoadingLayouts;
@Override
public void setLoadingDrawable(Drawable drawable) {
for (LoadingLayout layout : mLoadingLayouts) {
layout.setLoadingDrawable(drawable);
}
}
}
//被代理类
public abstract class LoadingLayout extends FrameLayout implements ILoadingLayout {
//真正的实现
public final void setLoadingDrawable(Drawable imageDrawable) {
// Set Drawable
mHeaderImage.setImageDrawable(imageDrawable);
mUseIntrinsicAnimation = (imageDrawable instanceof AnimationDrawable);
// Now call the callback
onLoadingDrawableSet(imageDrawable);
}
}
//在pullToRefresh中创建这个代理类
public abstract class PullToRefreshBase<T extends View> {
@Override
public final ILoadingLayout getLoadingLayoutProxy() {
return getLoadingLayoutProxy(true, true);
}
@Override
public final ILoadingLayout getLoadingLayoutProxy(boolean includeStart, boolean includeEnd) {
return createLoadingLayoutProxy(includeStart, includeEnd);
}
protected LoadingLayoutProxy createLoadingLayoutProxy(final boolean includeStart, final boolean includeEnd) {
LoadingLayoutProxy proxy = new LoadingLayoutProxy();
if (includeStart && mMode.showHeaderLoadingLayout()) {
proxy.addLayout(mHeaderLayout);
}
if (includeEnd && mMode.showFooterLoadingLayout()) {
proxy.addLayout(mFooterLayout);
}
return proxy;
}
}
//外界的使用
//外界要想设置loadingLayout的图片时, 都要通过代理类LoadingLayoutProxy间接操作LoadingLayout.
//这样就做到了控制外界对实际LoadingLayout对象的访问.
public class MostAccessFragment {
public PullToRefreshListView mPullToRefreshListView;
@Override
public void onThemeModeChanged(boolean isNightMode, int themeType, String themeId) {
mPullToRefreshListView.getLoadingLayoutProxy().setLoadingDrawable(
getResources().getDrawable(R.drawable.info_from_pc_pull_down_rolling_night));
}
PullToRefreshListView extends PullToRefreshBase
这样设计的好处是, 当给LoadingLayout对象设置图片时, 外界并不需要去知道它使用的PullToRefreshListView中当前存在几个LoadingLayout对象, 遍历有几个LoadingLayout对象的工作由代理类LoadingLayoutProxy去实现, 遍历后依次去调用每一个LoadingLayout对象去设置图片.
使用代理模式就做到了:
控制外界对LoadingLayout对象的直接访问.
远程代理模式 - 使用基于aidl的binder通信
之前在pullToRefresh中使用的代理模式可以称为普通的代理模式, 还有另一个名词 - 远程代理模式, 指的是代理类的对象和被代理类的对象不在同一个进程空间.
典型的应用场景就是基于aidl的binder通信.
Intent service;
ServiceConnection connection = new ServiceConnection(){
public void onServiceConnected(ComponetName name, IBinder service){
ITestService testService = ITestService.stub.asInterface(service);
//testService就是我们得到的远程代理对象
}
public void onServiceDisConnected(ComponentName name){
}
}
context.bindService(service,connection);
testService就是我们得到的远程代理对象.
在客户端调用testService对象的方法, 真正的实现在服务端实现了ITestService.stub()接口的Binder mBinder对象.
显然, 客户端的testService远程代理对象和服务端的mBinder这个被代理的对象, 不在同一个进程空间.
这就是远程代理的概念.
------DONE.-----------