# 常见设计模式四:代理模式
[TOC]
代理模式又称为委托模式,主要分为
1. 静态代理
2. 动态代理
代理模式的设计里面是限制对对象的直接访问,要想访问具体对象需要通过该对象的代理类去访问。
代理模式在很多地方是比较常见的,比如在 ARouter 内部,ARouter 的主要功能是通过其_ARouter 实现的,这里的 ARouter 就是_ARouter 的代理类。
```java
/**
* Init, it must be call before used router.
*/
public static void init(Application application) {
if (!hasInit) {
logger = _ARouter.logger;
_ARouter.logger.info(Consts.TAG, "ARouter init start.");
hasInit = _ARouter.init(application);
if (hasInit) {
_ARouter.afterInit();
}
_ARouter.logger.info(Consts.TAG, "ARouter init over.");
}
}
```
## 静态代理
静态代理主要分为下面三个部分:
1. 抽象接口 ISubject
2. 具体对象 RealSubject
3. 代理对象 ProxySubject
举个生活中我们使用代购替我们购买东西的例子。
创建购物抽象类:IShop
```java
public interface IShop {
void shop();
}
```
创建具体实际的购物抽象类:(朋友替我们购物)
```java
public class Friend implements IShop {
@Override
public void shop() {
System.out.println("朋友代替我们购物");
}
}
```
创建代理类:
```java
public class ProxyShop implements IShop {
/**
* 实际购物对象
*/
private IShop realShop;
public ProxyShop(IShop realShop) {
this.realShop = realShop;
}
@Override
public void shop() {
System.out.println("委托朋友代购");
realShop.shop();
System.out.println("朋友把代购的物品交给我们");
}
}
```
创建测试类:
```java
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
ProxyShop proxyShop = new ProxyShop(friend);
proxyShop.shop();
}
}
```
结果:

可以看到,朋友 friend 帮我们完成了购物动作,并且在代理类过程中,可以增加一些特殊的操作,在朋友帮我们代理购物的前后可以增加自定义操作。
## 动态代理
上面讲了静态代理,我们需要预先把需要的情况都要列出来,然后编写代理代码,需要自己生成编写代理类。
而动态代理就可以在运行时通过 Proxy.newProxyInstance生成代理类,比如我们有了新的需求,让朋友帮我们交话费,这个时候,就需要创建交话费的抽象,然后创建充话费的代理,这是很麻烦的,下面通过动态代理模式实现。
下面仍然以购物为例
抽象购物:
```java
public interface IShop {
void shop();
}
```
实际代理对象:Friend
```java
public class Friend implements IShop {
@Override
public void shop() {
System.out.println("朋友代替我们购物");
}
}
```
动态代理:
```java
public class DynamicProxyHandler implements InvocationHandler {
Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("委托朋友代购");
method.invoke(target,args);
System.out.println("朋友把代购的物品交给我们");
return null;
}
}
```
测试类:
```java
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(friend);
IShop shop = (IShop) Proxy.newProxyInstance(Friend.class.getClassLoader(),Friend.class.getInterfaces(),dynamicProxyHandler);
shop.shop();
}
}
```
运行结果:

这就是动态代理的大致流程。
需要注意的是,上面 DynamicProxyHandler 里面的 invoke 里面的代码,是在执行代理接口的里面的方法的时候才会被执行到,而不是创建代理对象的时候执行,所以这里我们就可以额外的加入一些操作,比如在朋友把代购物品交给我们以后,我们还要向朋友付钱,那么就可以:
```java
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
DynamicProxyHandler dynamicProxyHandler = new DynamicProxyHandler(friend);
IShop shop = (IShop) Proxy.newProxyInstance(Friend.class.getClassLoader(),Friend.class.getInterfaces(),dynamicProxyHandler);
shop.shop();
System.out.println("我们向朋友付了商品的价钱");
}
}
```
结果:

可以看到,我们可以在方法具体执行的前后加入一些自定义逻辑,更加灵活,而且在没修改原来方法的情况下,可以增强代码功能。
通过上面的实例可以发现:
静态代理的代理类需要自己编写,而动态代理的代理类则是由运行时使用 newProxyInstance 动态生成,
同时不管是静态代理还是动态代理,都需要实现接口,本质上是面对接口编程的,能够增加现有代码的功能。
区别 :
**静态代理**
静态代理业务类只需要关注业务逻辑本身,保证了业务类的重用性。代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,需要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法,增加了代码维护的复杂度。
**动态代理**
动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler invoke)。这样,在接口方法数量比较多的时候,可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使类职责更加单一,复用性更强。
一些参考地址
[轻松学,Java 中的代理模式及动态代理](https://blog.csdn.net/briblue/article/details/73928350#comments)
[从一道面试题开始说起 枚举、动态代理的原理](https://blog.csdn.net/lmj623565791/article/details/79278864)
- Java 面试题
- String、StringBuffer、StringBuilder 的区别?
- Java 中的四种引用
- 接口和抽象类的本质区别
- 集合框架
- 集合概述
- ArrayList 源码分析
- LinkedList 源码分析
- HashMap 源码分析
- LinkedHashMap 源码分析
- Android提供的 LruCache 的分析
- LinkedList 和 ArrayList 的区别
- 多线程
- 实现多线程的几种方式
- 线程的几种状态
- Thread 的 start() 和 run() 的区别
- sleep() 、yield() 和 wait() 的区别 ?
- notify() 和 notifyAll() 的区别?
- 保证线程安全的方式有哪几种?
- Synchronized 关键字
- volatile 和 synchronized 的区别?
- 如何正确的终止一个线程?
- ThreadLocal 原理分析
- 线程池
- 多线程的三个特征
- 五种线程池,四种拒绝策略,三种阻塞队列
- 给定三个线程如何顺序执行完以后在主线程拿到执行结果
- Java 内存模型
- 判定可回收对象算法
- equals 与 == 操作符
- 类加载机制
- 类加载简单例子
- 算法
- 时间、空间复杂度
- 冒泡排序
- 快速排序
- 链表反转
- IO
- 泛型
- Kolin 面试题
- Android 面试题
- Handler 线程间通信
- Message、MessageQueue、Looper、Handler 的对象关系
- Handler 使用
- Handler 源码分析
- HandlerThread
- AsyncTask
- IntentService
- 三方框架
- Rxjava
- rxjava 操作符有哪些
- 如何解决 RxJava 内存泄漏
- Rxjava 线程切换原理
- map和 flatmap 的区别
- Databinding引起的 java方法大于 65535 的问题
- Glide
- Glide 的缓存原理
- Glide 是如何和生命周期绑定的?不同的Context 有什么区别?
- Glide 、Picasso 、的区别,优劣势,如何选择?
- Jetpack
- 源码分析
- EventBus
- EventBus 源码分析
- RxBus 替代 EventBus
- OkHttp
- OkHttp 源码分析
- OkHttp 缓存分析
- RxPermission
- RxPermission 源码分析
- Retrofit
- create
- Retrofit 源码分析
- 优化
- 启动优化
- 布局优化
- 绘制优化
- 内存优化
- 屏幕适配
- 组件
- Activity
- Frgment
- Service
- ContentProvider
- BroadcastReceiver
- 进程间通信
- Binder机制和AIDL
- AILD 中的接口和普通的接口有什么区别
- in、out、inout 的区别
- Binder 为什么只需要拷贝一次
- 在android中,请简述jni的调用过程
- 生命周期
- Activity 生命周期
- Fragment 生命周期
- Service 生命周期
- onSaveInstanceState() 与 onRestoreIntanceState()
- 前沿技术
- 组件化
- 模块化
- 插件化
- 热更新
- UI - View
- Android 动画
- 事件分发机制
- WebView
- 系统相关
- 谈谈对 Context 的理解
- Android 版本
- App应用启动流程
- App 的打包
- App 的加固
- App 的安装
- Activity 启动流程
- ClassLoader
- Lru 算法加载 Bitmap 三级缓存原理
- Parcelable 和 Serializable 的区别
- Activity的启动流程
- 相关概念
- 网络相关
- Http
- Https
- Http 和 Https 的区别
- 为什么要进行三次握手和四次挥手?
- OkHttp使用Https访问服务器时信任所有证书
- 设计模式
- 单例模式
- 构建者模式
- 工厂模式
- 外观模式
- 代理模式
