在Android开发中,代理模式是一种常用的结构型设计模式,它允许通过代理对象控制对另一个对象(即目标对象)的访问。下面详细介绍代理模式及其在Android中的典型应用场景。

代理模式的核心概念

代理模式包含三个主要角色:

  1. 抽象主题(Subject):定义目标对象和代理对象的共同接口。
  2. 真实主题(RealSubject):实现抽象主题接口,是实际被访问的对象。
  3. 代理(Proxy):实现抽象主题接口,持有真实主题的引用,并在调用真实主题方法前后添加额外逻辑。

核心思想:通过代理对象间接访问目标对象,代理可以增强或控制对目标对象的访问。

Android中的代理模式实现

1. 静态代理示例

以下是一个静态代理的示例,用于在网络请求前后添加日志记录:

// 抽象主题接口
interface NetworkRequest {
    void sendRequest(String url);
}

// 真实主题类
class RealNetworkRequest implements NetworkRequest {
    @Override
    public void sendRequest(String url) {
        System.out.println("发送网络请求: " + url);
    }
}

// 代理类
class NetworkProxy implements NetworkRequest {
    private NetworkRequest realRequest;

    public NetworkProxy(NetworkRequest realRequest) {
        this.realRequest = realRequest;
    }

    @Override
    public void sendRequest(String url) {
        // 前置处理:添加请求日志
        System.out.println("日志: 请求开始 - " + url);
        
        // 调用真实对象方法
        realRequest.sendRequest(url);
        
        // 后置处理:添加响应日志
        System.out.println("日志: 请求完成 - " + url);
    }
}

// 使用示例
public class ProxyDemo {
    public static void main(String[] args) {
        NetworkRequest realRequest = new RealNetworkRequest();
        NetworkRequest proxy = new NetworkProxy(realRequest);
        proxy.sendRequest("https://api.example.com/data");
    }
}
2. 动态代理示例

动态代理通过Java反射机制在运行时创建代理对象,常用于权限检查场景:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 抽象主题接口
interface DatabaseOperation {
    void readData();
    void writeData(String data);
}

// 真实主题类
class RealDatabaseOperation implements DatabaseOperation {
    @Override
    public void readData() {
        System.out.println("读取数据库数据");
    }

    @Override
    public void writeData(String data) {
        System.out.println("写入数据: " + data);
    }
}

// 动态代理处理器
class PermissionHandler implements InvocationHandler {
    private Object target;

    public PermissionHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 权限检查
        if (!checkPermission(method.getName())) {
            System.out.println("错误:没有权限执行 " + method.getName());
            return null;
        }
        
        // 调用目标方法
        return method.invoke(target, args);
    }

    private boolean checkPermission(String methodName) {
        // 模拟权限检查逻辑
        return methodName.equals("readData") || hasWritePermission();
    }

    private boolean hasWritePermission() {
        System.out.println("检查写入权限...");
        return true; // 实际应用中会检查权限
    }
}

// 使用示例
public class DynamicProxyDemo {
    public static void main(String[] args) {
        DatabaseOperation realOperation = new RealDatabaseOperation();
        
        // 创建动态代理
        DatabaseOperation proxy = (DatabaseOperation) Proxy.newProxyInstance(
            DatabaseOperation.class.getClassLoader(),
            new Class<?>[]{DatabaseOperation.class},
            new PermissionHandler(realOperation)
        );
        
        proxy.readData();
        proxy.writeData("敏感数据");
    }
}

代理模式在Android中的典型应用场景

1. AIDL(远程代理)
  • 场景:跨进程通信(IPC)时,系统自动生成代理类处理底层通信细节。
  • 示例:
    // AIDL接口定义
    interface IRemoteService {
        void basicTypes(int anInt, long aLong, boolean aBoolean, ...);
    }
    
    // 系统生成的代理类会处理Binder通信细节
    
2. 图片加载(虚拟代理)
  • 场景:在图片加载完成前显示占位图,避免界面卡顿。
  • 示例:
    // 图片加载接口
    interface ImageLoader {
        void displayImage(String url, ImageView view);
    }
    
    // 真实加载器(耗时操作)
    class RealImageLoader implements ImageLoader { ... }
    
    // 虚拟代理(先显示占位图,再加载真实图片)
    class ImageLoaderProxy implements ImageLoader { ... }
    
3. 权限控制(保护代理)
  • 场景:在执行敏感操作前检查权限。
  • 示例:
    class CameraProxy implements CameraInterface {
        private RealCamera realCamera;
    
        @Override
        public void takePhoto() {
            if (checkPermission(Manifest.permission.CAMERA)) {
                realCamera.takePhoto();
            } else {
                requestPermission();
            }
        }
    }
    
4. 资源缓存(智能引用代理)
  • 场景:重复使用已加载的资源,减少开销。
  • 示例:
    class ResourceLoaderProxy implements ResourceLoader {
        private Map<String, Resource> cache = new HashMap<>();
        private RealResourceLoader realLoader;
    
        @Override
        public Resource load(String url) {
            if (cache.containsKey(url)) {
                return cache.get(url);
            }
            
            Resource res = realLoader.load(url);
            cache.put(url, res);
            return res;
        }
    }
    

代理模式的优缺点

优点:

  • 解耦:客户端与目标对象分离,降低耦合度。
  • 扩展性:可以在不修改目标对象的情况下增强功能。
  • 控制访问:代理可以限制或验证对目标对象的访问。

缺点:

  • 复杂性增加:需要创建额外的代理类,增加代码量。
  • 性能开销:动态代理使用反射,可能影响性能。

总结

代理模式是Android开发中的重要工具,尤其适合以下场景:

  • 需要在访问对象时添加额外逻辑(如日志、权限、缓存)。
  • 处理跨进程通信(AIDL)或延迟加载(虚拟代理)。
  • 控制对敏感资源的访问(保护代理)。

通过合理使用代理模式,可以提高代码的可维护性和可扩展性,同时遵循单一职责原则。

更多推荐