代理模式是一种设计模式,它提供了一种在不修改原始类代码的情况下,为其他对象提供接口的解决方案。代理模式分为静态代理和动态代理两种,其中静态代理是在编译时就已经确定了代理关系,而动态代理则是在运行时动态生成代理对象。全局规则和直连是代理模式中的两个重要概念,全局规则指的是所有代理对象都遵循相同的行为规范,而直连则是指代理对象直接与目标对象进行通信,而不经过代理层。通过使用代理模式,可以实现对目标对象的访问控制、性能优化等功能。
代理模式是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问,在这个模式中,一个类代表另一个类的功能,但允许你在不知道实际类的情况下调用其方法,代理模式通常用于以下场景:
1、系统需要在不修改原始类代码的情况下扩展功能。
2、需要对系统进行远程调用。
3、需要记录系统的操作日志。
4、需要实现延迟加载等功能。
代理模式的主要角色有:
1、抽象主题(Subject):定义了一组接口,表示系统中的某个实体,这个接口可以包含一些操作,如添加、删除、查询等。
2、具体主题(ConcreteSubject):实现了抽象主题接口,表示系统中的具体实体,这些实体可以是数据库中的表、文件系统中的文件等。
3、抽象代理(AbstractProxy):定义了一个接口,表示代理对象,这个接口包含一些操作,如获取、设置、删除等,具体代理(ConcreteProxy)实现了抽象代理接口,表示具体的代理对象,具体代理可以通过调用具体主题的方法来实现对抽象主题的操作。
4、静态代理(StaticProxy):在不依赖于具体主题对象的情况下,通过预先创建好的对象来实现代理功能,这种代理方式通常用于一些不需要动态创建代理对象的场景。
下面我们通过一个简单的例子来说明代理模式的使用:
假设我们有一个库存管理系统,其中有两个实体:商品(Product)和库存管理器(InventoryManager),商品具有一些属性,如名称、价格等;库存管理器负责管理商品的库存数量,我们希望在不修改商品类的情况下,实现对库存数量的增加和减少操作。
我们定义一个抽象主题接口:
public interface Product { String getName(); int getPrice(); }
我们定义一个具体主题类:
public class ConcreteProduct implements Product { private String name; private int price; public ConcreteProduct(String name, int price) { this.name = name; this.price = price; } @Override public String getName() { return name; } @Override public int getPrice() { return price; } }
我们定义一个抽象代理接口:
public interface InventoryManager { int addProduct(Product product); int reduceProduct(Product product); }
我们定义一个具体代理类:
public class ConcreteInventoryManager implements InventoryManager { private Product product; private int inventory; public ConcreteInventoryManager(Product product) { this.product = product; this.inventory = product.getPrice(); // 初始库存为商品价格 } @Override public int addProduct(Product product) { if (this.product == product) { // 如果是同一个商品,直接增加库存数量并返回结果 inventory += product.getPrice(); return inventory; } else { // 否则,创建一个新的代理对象并调用其addProduct方法 return new ConcreteInventoryManager((Product) product).addProduct(product); } } @Override public int reduceProduct(Product product) { if (this.product == product) { // 如果是同一个商品,直接减少库存数量并返回结果 inventory = Math.max(0, inventory - product.getPrice()); // 防止库存为负数的情况发生 return inventory; } else { // 否则,创建一个新的代理对象并调用其reduceProduct方法 return new ConcreteInventoryManager((Product) product).reduceProduct(product); } } }
我们在客户端代码中使用代理模式:
public class Client { public static void main(String[] args) throws Exception { Product product1 = new ConcreteProduct("Apple", 5); // 具体商品对象1,名称为"Apple",价格为5元/个 Product product2 = new ConcreteProduct("Banana", 3); // 具体商品对象2,名称为"Banana",价格为3元/个 InventoryManager inventoryManager = new ConcreteInventoryManager(product1); // 具体库存管理器对象,管理商品1的库存数量为5元/个的苹果数量+3元/个的香蕉数量=8元/个的水果总数量(初始状态) System.out.println("Before adding: " + inventoryManager.addProduct(product2)); // 在不修改库存管理器类的情况下,向其添加商品2,此时库存管理器的库存数量变为8+3=11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为11元/个的水果总数量(包括商品1和商品2)的水果总数量(初始状态)为17元/个的总价值。