目录
一、什么是代理?
代理模式定义了一个为其他对象提供一种代理以控制对这个对象的访问的接口。简单来说,代理对象充当了真实对象(被代理对象)的替身,客户端通过代理对象间接访问真实对象,而不是直接访问。这种机制允许在不修改原有对象结构的情况下,对访问行为进行控制或增强。
代理模式的核心在于“代理”二字,它可以是访问控制、性能优化、远程调用、缓存等多种功能的载体。通过代理,我们可以在不改变原有对象代码的前提下,增加额外的行为或逻辑处理。
二、代理的目的
- 控制访问:通过代理对象的方式间接的访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性
- 功能增强:通过代理业务对原有业务进行增强
三、如何实现代理
3.1 静态代理
静态代理是指代理类在编译时已经确定,与目标类实现了相同的接口,并在调用目标类的方法时添加额外的行为。
首先,我们定义了两个接口ByClothes和ByShoot,分别用于卖衣服和卖鞋子的操作。
// ByClothes.java
package com.代理;
public interface ByClothes {
void clothes(String size);
}
// ByShoot.java
package com.代理;
public interface ByShoot {
void Shoot(String size);
}
接着,我们实现了这两个接口的目标类ClothesFactory和ShootFactory。
// ClothesFactory.java
package com.代理;
public class ClothesFactory implements ByClothes {
public void clothes(String size) {
System.out.println("已经为您定制好了一件大小为" + size + "的衣服");
}
}
// ShootFactory.java
package com.代理;
public class ShootFactory implements ByShoot {
public void Shoot(String size) {
System.out.println("已经为您定制好了一件大小为" + size + "的鞋子");
}
}
然后,我们创建了一个代理类Proxy,它实现了ByClothes接口,并在调用ClothesFactory的方法前后添加了前置服务和后置服务。
// Proxy.java
package com.代理;
public class Proxy implements ByClothes {
private ClothesFactory clothesFactory = new ClothesFactory();
private ShootFactory shootFactory = new ShootFactory();
@Override
public void clothes(String size) {
FontService();
clothesFactory.clothes(size);
EndService();
}
public void FontService() {
System.out.println("根据您的需求进行市场调研");
}
public void EndService() {
System.out.println("为您提供一条龙报办服务");
}
}
在Test类中,我们通过代理类Proxy来调用ClothesFactory的方法。
// Test.java (部分代码)
public class Test {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.clothes("xL");
}
}
代码执行输出为:
然而,静态代理的一个主要缺点是,当目标类增多时,代理类需要实现所有目标类的接口,这会导致代理类变得臃肿且难以维护。
3.2 动态代理
动态代理是指在运行时动态地创建代理对象,而不需要事先定义代理类。Java中的动态代理主要依赖于java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
首先,我们定义一个动态代理处理器DyProxy,它实现了InvocationHandler接口。
// DyProxy.java
package com.代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DyProxy implements InvocationHandler {
private Object o;
public DyProxy(Object o) {
this.o = o;
}
public Object getDyProxyInterFace() {
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
FontService();
Object result = method.invoke(o, args);
EndService();
return result;
}
public void FontService() {
System.out.println("根据您的需求进行市场调研");
}
public void EndService() {
System.out.println("为您提供一条龙报办服务");
}
}
在Test类中,我们使用动态代理来调用ClothesFactory和ShootFactory的方法。
// Test.java (完整代码)
package com.代理;
public class Test {
public static void main(String[] args) {
// 静态代理调用
// Proxy proxy = new Proxy();
// proxy.clothes("xL");
// 动态代理调用ClothesFactory
ClothesFactory clothesFactory = new ClothesFactory();
ByClothes clothes = (ByClothes) new DyProxy(clothesFactory).getDyProxyInterFace();
clothes.clothes("L");
// 动态代理调用ShootFactory
ShootFactory shootFactory = new ShootFactory();
ByShoot shoot = (ByShoot) new DyProxy(shootFactory).getDyProxyInterFace();
shoot.Shoot("38");
}
}
代码执行输出为:
通过动态代理,我们可以在不修改目标类代码的情况下,为目标类的方法添加额外的行为。动态代理的优势在于其灵活性和可扩展性,可以轻松地为目标类添加代理逻辑,而无需为每个目标类创建单独的代理类。
总结
代理模式是一种强大且灵活的设计模式,它通过引入代理对象来控制对真实对象的访问,提供了访问控制、性能优化、远程调用、安全增强等多种可能性。本文详细讲解了Java中的代理模式,包括静态代理和动态代理。静态代理通过实现目标类的接口来创建代理类,并在调用目标类方法时添加额外的行为。然而,静态代理的缺点是当目标类增多时,代理类会变得臃肿且难以维护。动态代理则通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口在运行时动态地创建代理对象,从而避免了静态代理的缺点。动态代理具有更高的灵活性和可扩展性,是Java中实现代理模式的一种优雅方式。