一、故事解说:明星的经纪人如何工作
假设你是一位顶流明星,每天有很多事务:
-
你专注核心业务:唱歌、演戏,不需要关心签合同、谈广告等杂事;
-
经纪人作为代理:
- 粉丝想找你演出,先联系经纪人(代理);
- 经纪人负责谈价格、签合同,最后把演出机会交给你;
-
对外统一接口:粉丝看到的是经纪人处理所有事务,但实际做事的是你。
静态代理核心:代理对象(经纪人)和真实对象(明星)实现相同接口,代理负责预处理 / 后处理,真实对象专注核心逻辑。
二、静态代理核心结构(明星经纪人案例)
java
// 1. 共同接口:明星需要做的事情
interface Star {
void sing(); // 唱歌
void act(); // 演戏
}
// 2. 真实明星:核心逻辑实现
class RealStar implements Star {
@Override
public void sing() {
System.out.println("明星正在唱歌,收费100万");
}
@Override
public void act() {
System.out.println("明星正在演戏,收费500万");
}
}
// 3. 代理明星(经纪人):处理杂事,调用真实明星
class StarAgent implements Star {
private RealStar realStar;
public StarAgent(RealStar realStar) {
this.realStar = realStar;
}
@Override
public void sing() {
// 预处理:谈价格、签合同
System.out.println("经纪人:谈唱歌合作,签合同,抽成20%");
realStar.sing(); // 调用真实明星的方法
// 后处理:收款、开发票
System.out.println("经纪人:收款,开发票");
}
@Override
public void act() {
System.out.println("经纪人:谈演戏合作,签合同,抽成20%");
realStar.act();
System.out.println("经纪人:收款,开发票");
}
}
// 使用方式
Star star = new StarAgent(new RealStar());
star.sing(); // 输出:经纪人处理流程 + 明星唱歌
三、Android 常用静态代理案例与实现
案例 1:View 点击事件的代理(类似 OnClickListener)
java
// 1. 共同接口:点击事件
interface OnClickListener {
void onClick(View v);
}
// 2. 真实点击逻辑:Activity中的点击处理
class RealOnClickListener implements OnClickListener {
@Override
public void onClick(View v) {
System.out.println("真实逻辑:跳转到详情页");
}
}
// 3. 代理点击逻辑:添加权限检查
class PermissionClickProxy implements OnClickListener {
private OnClickListener realClickListener;
private Context context;
public PermissionClickProxy(Context context, OnClickListener realClickListener) {
this.context = context;
this.realClickListener = realClickListener;
}
@Override
public void onClick(View v) {
// 预处理:检查权限
if (checkPermission(context)) {
realClickListener.onClick(v); // 调用真实逻辑
} else {
System.out.println("代理:权限不足,提示用户授权");
}
}
private boolean checkPermission(Context context) {
// 实际中检查权限
return true;
}
}
// 在Activity中使用
View button = findViewById(R.id.button);
OnClickListener realClick = v -> {
// 真实点击逻辑
};
OnClickListener proxyClick = new PermissionClickProxy(this, realClick);
button.setOnClickListener(proxyClick);
优点:
-
功能扩展灵活:不修改原点击逻辑,通过代理添加权限检查、日志记录等功能;
-
职责分离:真实逻辑专注业务(跳转页面),代理专注权限控制;
-
符合 Android 事件模型:类似 Android 的
OnClickListener,代理模式是事件处理的核心思想。
缺点:
- 类数量增加:每个代理功能需要一个代理类,复杂场景下类数爆炸;
- 静态绑定:代理关系在编译时确定,无法动态切换代理(如不同场景用不同代理)。
案例 2:Service 的代理(后台任务预处理)
java
// 1. 共同接口:Service的生命周期
interface Service {
void onCreate();
void onStartCommand(Intent intent, int flags, int startId);
void onDestroy();
}
// 2. 真实Service:处理核心业务
class RealService implements Service {
@Override
public void onCreate() {
System.out.println("真实Service:初始化数据库");
}
@Override
public void onStartCommand(Intent intent, int flags, int startId) {
System.out.println("真实Service:处理网络请求");
}
@Override
public void onDestroy() {
System.out.println("真实Service:释放资源");
}
}
// 3. 代理Service:添加日志和权限检查
class ServiceProxy implements Service {
private RealService realService;
private Context context;
public ServiceProxy(Context context) {
this.context = context;
this.realService = new RealService();
}
@Override
public void onCreate() {
System.out.println("代理:记录日志 - Service创建");
if (checkPermission(context)) {
realService.onCreate();
} else {
System.out.println("代理:权限不足,Service创建失败");
}
}
@Override
public void onStartCommand(Intent intent, int flags, int startId) {
System.out.println("代理:记录日志 - Service启动");
realService.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
System.out.println("代理:记录日志 - Service销毁");
realService.onDestroy();
}
private boolean checkPermission(Context context) {
return true; // 实际中检查权限
}
}
// 使用方式(类似Android中启动Service)
Service service = new ServiceProxy(context);
service.onCreate();
service.onStartCommand(intent, flags, startId);
优点:
-
非侵入式扩展:不修改原 Service 代码,通过代理添加日志、权限等功能;
-
符合 Android 组件设计:Service 本身是代理模式的应用(Activity 通过代理与 Service 通信);
-
预处理 / 后处理灵活:可在调用真实 Service 前后添加任意逻辑。
缺点:
- 紧耦合:代理类直接依赖真实 Service,若真实 Service 接口变更,代理类也需修改;
- 无法代理多个对象:一个代理只能对应一个真实 Service 实例,复用性低。
案例 3:网络请求的代理(添加请求拦截)
java
// 1. 共同接口:网络请求
interface NetworkService {
String request(String url);
}
// 2. 真实网络请求:Retrofit或OkHttp的封装
class RealNetworkService implements NetworkService {
@Override
public String request(String url) {
System.out.println("真实请求:发送HTTP请求到" + url);
return "请求结果";
}
}
// 3. 代理网络请求:添加请求头、日志、缓存检查
class NetworkProxy implements NetworkService {
private NetworkService realService;
public NetworkProxy(NetworkService realService) {
this.realService = realService;
}
@Override
public String request(String url) {
// 预处理1:添加请求头
url = addHeaders(url);
// 预处理2:检查缓存
String cacheResult = checkCache(url);
if (cacheResult != null) {
return cacheResult;
}
// 调用真实请求
String result = realService.request(url);
// 后处理:保存缓存
saveToCache(url, result);
return result;
}
private String addHeaders(String url) {
System.out.println("代理:添加请求头(token、user-agent)");
return url;
}
private String checkCache(String url) {
System.out.println("代理:检查缓存");
return null; // 实际中返回缓存结果
}
private void saveToCache(String url, String result) {
System.out.println("代理:保存结果到缓存");
}
}
// 使用方式
NetworkService service = new NetworkProxy(new RealNetworkService());
String result = service.request("https://api.example.com/data");
优点:
-
拦截器模式基础:网络请求的拦截器(如添加 token、日志)本质是代理模式;
-
性能优化:通过代理实现缓存检查,避免重复请求;
-
符合 Android 网络框架设计:OkHttp 的 Interceptor、Retrofit 的 CallAdapter 本质是代理。
缺点:
- 代理链过长:多层代理(日志代理→缓存代理→权限代理)会增加调用栈深度,影响性能;
- 静态配置限制:代理关系固定,无法在运行时动态切换代理策略(如无网络时切换到缓存代理)。
四、静态代理的适用场景与总结
适用场景:
- 功能扩展:在不修改原代码的情况下,添加预处理 / 后处理逻辑(如权限检查、日志记录);
- 访问控制:限制对真实对象的直接访问(如代理 Service 控制权限);
- 性能优化:通过代理实现缓存、懒加载(如网络请求先查缓存);
- 接口隔离:代理作为中间层,隔离客户端与复杂的真实对象(如 View 的事件代理)。
核心优点:
- 结构简单:相比动态代理,静态代理代码更直观,易于理解;
- 编译时安全:代理关系在编译时确定,避免运行时异常;
- 职责清晰:代理专注于非核心功能,真实对象专注核心逻辑。
核心缺点:
- 类数量爆炸:每个代理功能需要独立的代理类,项目庞大时难以维护;
- 缺乏灵活性:代理关系固定,无法在运行时动态改变(如根据条件选择不同代理);
- 紧耦合:代理类与真实类绑定,真实类接口变更会影响代理类。
Android 中的最佳实践:
-
优先使用系统代理:如 View 的事件代理、Handler 的 Callback 代理,避免重复造轮子;
-
小型功能代理:用于简单的功能扩展(如点击事件添加权限检查),复杂场景改用动态代理;
-
结合接口编程:代理类依赖接口而非实现类,提高代码可维护性(如
NetworkService接口而非具体实现)。
静态代理是 Android 框架的基础设计思想之一,理解它有助于深入掌握 View 事件机制、Service 通信、网络请求等核心模块的工作原理。