一、概念与定义

代理模式(Proxy Pattern)‌ 是一种结构型设计模式,它通过一个代理对象来控制对另一个对象(目标对象)的访问。代理模式的核心思想是‌“间接访问”‌,即客户端不直接访问目标对象,而是通过代理对象间接访问。


二、基本结构

代理模式由以下四个角色组成:

角色描述
抽象主题:Subject定义目标对象和代理的公共接口(如业务方法)。
真实主题:RealSubject实际目标对象,实现具体的业务逻辑。
代理主题:Proxy代理类,持有目标对象引用,控制对其的访问并添加额外的功能。
客户端:Client使用代理主题或真实主题的代码。
  1. 抽象主题(Subject)

    • 定义目标对象和代理对象的共同接口,使得客户端无法区分目标对象和代理对象。
  2. 真实主题(Real Subject)

    • 实际实现业务逻辑的对象,代理模式的主要目标是控制对它的访问。
  3. 代理主题(Proxy)

    • 代理类,负责控制对真实主题的访问,并可以添加额外的功能(如日志记录、权限验证等)。
  4. 客户端(Client)

    • 使用代理主题或真实主题的代码。

三、代理模式的类型

代理模式可以分为以下几种常见的类型:

  1. 远程代理(Remote Proxy)

    • 用于隐藏远程对象的物理位置,使得客户端可以像操作本地对象一样操作远程对象。
  2. 虚拟代理(Virtual Proxy)

    • 用于优化性能,延迟加载资源(如图片、视频等)。
  3. 保护代理(Protection Proxy)

    • 用于控制对真实主题的访问权限,根据客户端的权限决定是否允许访问。
  4. 智能代理(Smart Proxy)

    • 在访问真实主题时,自动添加额外的功能,如日志记录、缓存、计数器等。

四、生活场景类比

外卖配送场景

  • 真实主题(Real Subject)‌:外卖骑手,负责实际送餐。
  • 代理主题(Proxy)‌:外卖平台,接收订单并分配给骑手。
  • 客户端(Client)‌:用户通过外卖平台下单,而不是直接联系骑手。

流程‌:

  1. 用户通过外卖平台下单。
  2. 外卖平台(代理)接收订单并分配给骑手(真实主题)。
  3. 骑手完成送餐任务。

通过代理模式,用户无需直接与骑手打交道,而是通过平台完成整个流程,从而简化了操作。


五、Java代码示例

1. 完整代码结构

(1)抽象主题(Subject)
//Subject接口:定义订单处理规范
interface DeliveryService {
	// 调用骑手送餐
	void placeOrder(String orderId, String address);
}
(2)真实主题(Real Subject)
//RealSubject:骑手(真实送餐对象)
class Rider implements DeliveryService {
	@Override
	public void placeOrder(String orderId, String address) {
		System.out.println("[骑手] 订单号 " + orderId + " 已接单,送往地址: " + address);
		deliverFood(orderId);
	}

	private void deliverFood(String orderId) {
		System.out.println("[骑手] 配送中... 订单号: " + orderId);
		System.out.println("[骑手] 订单号 " + orderId + " 已完成配送!");
	}
}
(3)代理主题(Proxy)
//Proxy:外卖平台(代理订单分配与验证)
class FoodDeliveryPlatform implements DeliveryService {
	private Rider rider; // 持有真实骑手对象

	private boolean isOrderValid(String orderId) {
		// 模拟订单验证逻辑(如校验地址、支付状态等)
		return !orderId.isEmpty();
	}

	@Override
	public void placeOrder(String orderId, String address) {
		System.out.println("[平台] 接收到订单: " + orderId + ",地址: " + address);

		// 代理附加逻辑:订单校验
		if (!isOrderValid(orderId)) {
			System.out.println("[平台] 错误!订单号无效,配送终止。");
			return;
		}

		System.out.println("[平台] 订单校验通过,分配骑手中...");

		// 延迟初始化骑手(模拟资源优化)
		if (rider == null) {
			rider = new Rider();
		}

		// 调用真实骑手送餐
		rider.placeOrder(orderId, address);

		// 代理附加逻辑:记录日志
		System.out.println("[平台] 订单号 " + orderId + " 配送流程已记录。");
	}
}
(4)客户端(ClientApp)
//4. 客户端(用户下单)
public class ClientApp {
	public static void main(String[] args) {
		// 用户直接与外卖平台(代理)交互
		DeliveryService platform = new FoodDeliveryPlatform();

		// 正常订单
		platform.placeOrder("ORDER_202502241001", "北京市朝阳区");
		System.out.println("---------------");

		// 无效订单(空订单号)
		platform.placeOrder("", "上海市浦东新区");
	}
}

运行结果

[平台] 接收到订单: ORDER_202502241001,地址: 北京市朝阳区
[平台] 订单校验通过,分配骑手中...
[骑手] 订单号 ORDER_202502241001 已接单,送往地址: 北京市朝阳区
[骑手] 配送中... 订单号: ORDER_202502241001
[骑手] 订单号 ORDER_202502241001 已完成配送!
[平台] 订单号 ORDER_202502241001 配送流程已记录。
---------------
[平台] 接收到订单: ,地址: 上海市浦东新区
[平台] 错误!订单号无效,配送终止。

六、代理模式的特点

  1. 透明性

    • 客户端无法区分真实主题和代理主题,两者具有相同的接口。
  2. 间接访问

    • 客户端通过代理间接访问真实主题。
  3. 额外功能

    • 代理可以在不修改真实主题代码的情况下,为客户端添加额外的功能(如日志记录、权限验证等)。
  4. 灵活性

    • 代理模式可以在不修改真实主题的情况下,灵活地扩展功能。

七、适用场景

  1. 远程访问

    • 用于隐藏远程对象的物理位置,提供透明的访问方式。
  2. 延迟加载

    • 用于优化性能,延迟加载资源(如图片、视频等)。
  3. 权限控制

    • 用于控制对真实主题的访问权限,根据客户端的权限决定是否允许访问。
  4. 功能扩展

    • 在不修改真实主题的情况下,通过代理添加额外的功能(如日志记录、缓存等)。

八、优缺点

优点

  1. 透明性

    • 客户端无需修改代码即可使用代理。
  2. 灵活性

    • 可以在不修改真实主题的情况下,灵活地扩展功能。
  3. 优化性能

    • 通过延迟加载或缓存等技术优化系统性能。
  4. 控制访问

    • 可以通过代理控制对真实主题的访问权限。

缺点

  1. 增加复杂性

    • 引入代理类会增加系统的复杂性。
  2. 额外开销

    • 代理模式可能会带来额外的性能开销(如方法调用的额外步骤)。
  3. 维护成本

    • 需要维护代理类和真实主题类之间的同步。

九、总结

代理模式通过引入代理对象,间接地控制对真实主题的访问。它具有透明性、灵活性和扩展性等优点,适用于需要控制访问权限、优化性能或扩展功能的场景。在实际开发中,代理模式可以显著提高系统的灵活性和可维护性。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐