学而不思则罔,思而不学则殆
【设计模式】代理模式(Proxy Pattern)
我发现一个很常见的现象,很多文章都在讲设计模式,代理模式,但是呢没有举出一些项目或者实际工作用到的例子,我感觉这样不能加深我们的理解,感觉只是一个知识点,而没有实际的运用,所以本篇文章根据个人理解,总结了三个常用的代理模式,有理解不对的地方,欢迎指出,共同进步。
代理模式
Proxy Pattern 代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
常见代理模式
静态代理
静态代理类图
Demo
interface Subject {
void request();
}
static class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
}
static class Proxy implements Subject {
Subject subject;
@Override
public void request() {
if (subject == null) {
subject = new RealSubject();
}
subject.request();
}
}
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.request();
}
动态代理
动态代理Demo
interface Subject {
void request();
int add(int a, int b);
}
static class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject request");
}
@Override
public int add(int a, int b) {
return a + b;
}
}
//测试动态代理
private static void test1() {
Subject proxyInstance = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new
Class[]{Subject.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理 前 proxy:" + proxy.getClass() + " method:" + method + " args:" + Arrays.toString(args));
RealSubject realSubject = new RealSubject();
Object result = method.invoke(realSubject, args);
System.out.println("动态代理 后");
return result;
}
});
System.out.println("proxyInstance:" + proxyInstance);
System.out.println("proxyInstance.toString:" + proxyInstance.toString());
System.out.println("proxyInstance.hashCode:" + proxyInstance.hashCode());
proxyInstance.request();
System.out.println("add(2,3):" + proxyInstance.add(2, 3));
}
动态代理有三个参数【Proxy.newProxyInstance()】:
- ClassLoader loader 指定当前目标对象使用的类加载器,获取加载器的方法是固定的
- Class<?>[] interfaces 指定目标对象实现的接口的类型,使用泛型方式确认类型
- InvocationHandler h 指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
测试结果如下:
动态代理 前 proxy:class com.pattern.$Proxy0 method:public java.lang.String java.lang.Object.toString() args:null
动态代理 后
proxyInstance:com.pattern.ProxyPattern$RealSubject@5e2de80c
动态代理 前 proxy:class com.pattern.$Proxy0 method:public java.lang.String java.lang.Object.toString() args:null
动态代理 后
proxyInstance.toString:com.pattern.ProxyPattern$RealSubject@1d44bcfa
动态代理 前 proxy:class com.pattern.$Proxy0 method:public native int java.lang.Object.hashCode() args:null
动态代理 后
proxyInstance.hashCode:644117698
动态代理 前 proxy:class com.pattern.$Proxy0 method:public abstract void com.pattern.ProxyPattern$Subject.request() args:null
RealSubject request
动态代理 后
动态代理 前 proxy:class com.pattern.$Proxy0 method:public abstract int com.pattern.ProxyPattern$Subject.add(int,int) args:[2, 3]
动态代理 后
add(2,3):5
我发现不止调用接口的方法request和add方法,就算调用常规的toString和hashCode方法也会调用invoke方法,走动态代理的逻辑。
代理模式应用
网络代理
Charles网络抓包工具,当我们使用本地代理或者远程代理的时候,就是一种代理模式。我们只管从Charles中获取数据,至于Charlei内部数据从本地还是从网络我都不关心
Android的Context
Context源码如下:查看其中重要的部分。
public class ContextWrapper extends Context {
@UnsupportedAppUsage
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
...
public Context getBaseContext() {
return mBase;
}
@Override
public AssetManager getAssets() {
return mBase.getAssets();
}
@Override
public Resources getResources() {
return mBase.getResources();
}
@Override
public PackageManager getPackageManager() {
return mBase.getPackageManager();
}
@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}
@Override
public Looper getMainLooper() {
return mBase.getMainLooper();
}
@Override
public Executor getMainExecutor() {
return mBase.getMainExecutor();
}
@Override
public Context getApplicationContext() {
return mBase.getApplicationContext();
}
...
}
Context类图
Java中的ReentrantLock
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
...
public void lock() {
sync.lock();
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public void unlock() {
sync.release(1);
}
public Condition newCondition() {
return sync.newCondition();
}
public int getHoldCount() {
return sync.getHoldCount();
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public boolean isLocked() {
return sync.isLocked();
}
public final boolean isFair() {
return sync instanceof FairSync;
}
protected Thread getOwner() {
return sync.getOwner();
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
public final int getQueueLength() {
return sync.getQueueLength();
}
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
...
}
查看ReentrantLock 的源码,保留其中的重要方法,我的理解这是一种很直接的代理模式的应用,所有的工作都是sync对象在实现和工作的,而ReentrantLock只是sync的一个代表。
RxJava中的Observer(订阅者)接口
RxJava的几十上百个操作符内部都是采用代理模式(个人理解)。当我们建立订阅的时候,每一个Observable内部都会新建一个新的Observer,新建的Observer持有我们建立订阅关系时传入的Observer对象,然后在用内部新建的Observer对象去订阅上一级的Observable,接收上一级下发的消息,依次类推。
随便举一个例子:
static final class InnerObserver<U> extends AtomicReference<Disposable> implements Observer<U> {
private static final long serialVersionUID = -7449079488798789337L;
final Observer<? super U> downstream;
final SourceObserver<?, ?> parent;
InnerObserver(Observer<? super U> actual, SourceObserver<?, ?> parent) {
this.downstream = actual;
this.parent = parent;
}
@Override
public void onSubscribe(Disposable d) {
DisposableHelper.replace(this, d);
}
@Override
public void onNext(U t) {
downstream.onNext(t);
}
@Override
public void onError(Throwable t) {
parent.dispose();
downstream.onError(t);
}
@Override
public void onComplete() {
parent.innerComplete();
}
void dispose() {
DisposableHelper.dispose(this);
}
}
}
InnerObserver是内部downstream(真实观察者)的代表。