目录
定义
代理模式(Proxy Pattern)是一种结构型设计模式,它允许我们为某个对象提供一个代理对象,并由代理对象控制对原对象的访问。这种设计模式可以在不改变原始类(或称为被代理类)代码的情况下,通过引入代理类来给原始类附加功能。
代理模式的类型
代理设计模式可以根据代理的创建方式和使用场景分为静态代理和动态代理两种类型。
静态代理
静态代理是指在编译阶段就已经确定的代理类。开发者需要为每一个目标对象手动编写一个代理类,这个代理类包含了对目标对象的引用,并在调用目标对象的方法前后可以执行一些额外的操作。通常,代理类和目标类会实现相同的接口或继承相同的父类,以确保它们可以在结构上互相替换。
特点:
- 代理类和目标类在编译时期就已经确定。
- 需要为每个目标类单独创建代理类,可能导致代码重复。
- 适用于代理类较少且功能相对固定的场景。
为了更清晰地阐述,让我们通过一个贴近生活的实例来说明:假设有位房东想要出租自己的房子,但又不愿意亲自处理与租客的沟通和租赁细节。为此,他决定委托一家房屋中介公司来全权负责租赁过程。首先,我们定义了一个名为RentService的租房服务接口。
java
public interface RentService {
void rentHouse(String tenantName, String houseType);
}
然后,我们创建了一个名为Landlord的房东类,该类实现了RentService接口。
java
public class Landlord implements RentService {
@Override
public void rentHouse(String tenantName, String houseType) {
System.out.println(tenantName + " rented a " + houseType + " from the landlord.");
}
}
接着,我们再创建一个名为HouseProxy的静态代理类,这个类代表房屋中介公司,并且同样实现了RentService接口。HouseProxy不仅负责调用Landlord类中的基本租房服务方法,还在这些服务的前后嵌入了额外的中介服务功能。这些附加服务包括合同的签订、物业的检查、以及租赁期间的管理等,从而确保了整个租赁过程的顺利进行,并为房东和租客提供了更加全面和专业的服务。
java
public class HouseProxy implements RentService {
private final Landlord landlord;
public HouseProxy(Landlord landlord) {
this.landlord = landlord;
}
@Override
public void rentHouse(String tenantName, String houseType) {
System.out.println("Agent preparing contract for " + tenantName + "...");
landlord.rentHouse(tenantName, houseType);
System.out.println("Agent conducting property inspection...");
}
}
最后,我们创建一个客户端类来演示如何使用这个代理类。
java
public class Client {
public static void main(String[] args) {
HouseProxy proxy = new HouseProxy(new Landlord());
proxy.rentHouse("张三","两室一厅");
// 输出:
// Agent preparing contract for 张三...
// 张三 rented a 两室一厅 from the landlord.
// Agent conducting property inspection...
}
}
在这个例子中,HouseProxy就是一个静态代理,它在房东提供的基础服务之上,增加了额外的中介服务流程,而这些流程是特定于中介服务的,不改变原始的租房逻辑。
动态代理
动态代理是一种在程序运行时动态生成代理对象的方式,而不是预先为每个目标对象创建固定的代理类。这种机制允许代理类在运行时根据实际的方法调用动态地生成,从而提供了更大的灵活性。
特点:
- 代理类在运行时根据目标类动态生成。
- 可以用一个代理类代理多个目标对象,提高代码复用。
- 提供更高的灵活性和扩展性,适合于需要在运行时决定代理行为的场景。
实现方式:
- JDK动态代理:基于Java反射机制实现,利用InvocationHandler接口和Proxy类,要求目标类实现接口。
java
public class RentServiceInvocationHandler implements InvocationHandler {
private final RentService target;
public RentServiceInvocationHandler(RentService target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("Agent preparing contract for " + args[0] + "...");
Object result = method.invoke(target, args);
System.out.println("Agent conducting property inspection...");
return result;
}
}
public class Client {
public static void main(String[] args) {
RentService dynamicProxy = (RentService) Proxy.newProxyInstance(
RentService.class.getClassLoader(),
new Class[]{RentService.class},
new RentServiceInvocationHandler(new Landlord())
);
dynamicProxy.rentHouse("张三", "两室一厅");
}
}
- CGLIB动态代理:通过字节码操作库生成目标类的子类,适用于无接口的情况。
java
public class LandlordInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Agent preparing contract for " + args[0] + "...");
Object result = proxy.invokeSuper(obj, args);
System.out.println("Agent conducting property inspection...");
return result;
}
}
public class CglibProxyFactory {
public static Landlord createLandlordProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Landlord.class);
enhancer.setCallback(new LandlordInterceptor());
return (Landlord) enhancer.create();
}
}
public class Client {
public static void main(String[] args) {
Landlord landlordProxy = CglibProxyFactory.createLandlordProxy();
landlordProxy.rentHouse("张三", "两室一厅");
}
}
总结
代理设计模式是一种强大且灵活的设计模式,它可以在不修改原始类代码的情况下为原始类添加额外的功能。通过静态代理和动态代理两种方式,我们可以根据具体的应用场景选择合适的实现方式。同时,我们也需要注意到代理设计模式的优缺点,以便在实际应用中做出最佳的选择。