静态代理:用明星与经纪人的故事理解代理模式

86 阅读6分钟

一、故事解说:明星的经纪人如何工作

假设你是一位顶流明星,每天有很多事务:

  1. 你专注核心业务:唱歌、演戏,不需要关心签合同、谈广告等杂事;

  2. 经纪人作为代理

    • 粉丝想找你演出,先联系经纪人(代理);
    • 经纪人负责谈价格、签合同,最后把演出机会交给你;
  3. 对外统一接口:粉丝看到的是经纪人处理所有事务,但实际做事的是你。

静态代理核心:代理对象(经纪人)和真实对象(明星)实现相同接口,代理负责预处理 / 后处理,真实对象专注核心逻辑。

二、静态代理核心结构(明星经纪人案例)

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 本质是代理。

缺点

  • 代理链过长:多层代理(日志代理→缓存代理→权限代理)会增加调用栈深度,影响性能;
  • 静态配置限制:代理关系固定,无法在运行时动态切换代理策略(如无网络时切换到缓存代理)。

四、静态代理的适用场景与总结

适用场景

  1. 功能扩展:在不修改原代码的情况下,添加预处理 / 后处理逻辑(如权限检查、日志记录);
  2. 访问控制:限制对真实对象的直接访问(如代理 Service 控制权限);
  3. 性能优化:通过代理实现缓存、懒加载(如网络请求先查缓存);
  4. 接口隔离:代理作为中间层,隔离客户端与复杂的真实对象(如 View 的事件代理)。

核心优点

  • 结构简单:相比动态代理,静态代理代码更直观,易于理解;
  • 编译时安全:代理关系在编译时确定,避免运行时异常;
  • 职责清晰:代理专注于非核心功能,真实对象专注核心逻辑。

核心缺点

  • 类数量爆炸:每个代理功能需要独立的代理类,项目庞大时难以维护;
  • 缺乏灵活性:代理关系固定,无法在运行时动态改变(如根据条件选择不同代理);
  • 紧耦合:代理类与真实类绑定,真实类接口变更会影响代理类。

Android 中的最佳实践

  • 优先使用系统代理:如 View 的事件代理、Handler 的 Callback 代理,避免重复造轮子;

  • 小型功能代理:用于简单的功能扩展(如点击事件添加权限检查),复杂场景改用动态代理;

  • 结合接口编程:代理类依赖接口而非实现类,提高代码可维护性(如NetworkService接口而非具体实现)。

静态代理是 Android 框架的基础设计思想之一,理解它有助于深入掌握 View 事件机制、Service 通信、网络请求等核心模块的工作原理。