您好,登录后才能下订单哦!
代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过创建一个代理对象来控制对另一个对象的访问。代理对象作为客户端和目标对象之间的中介,可以在不改变目标对象的情况下,增加额外的功能或控制访问。
代理模式在以下场景中非常有用:
优点:
缺点:
代理模式可以通过多种方式实现,主要包括静态代理和动态代理。下面我们将详细介绍这两种实现方式。
静态代理是指在编译时就已经确定了代理类和目标类的关系。代理类和目标类都实现了相同的接口,代理类在调用目标类的方法前后可以执行额外的操作。
// 1. 定义接口
interface Subject {
void request();
}
// 2. 实现目标类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 3. 实现代理类
class ProxySubject implements Subject {
private RealSubject realSubject;
public ProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("ProxySubject: Before handling request.");
realSubject.request();
System.out.println("ProxySubject: After handling request.");
}
}
// 4. 客户端调用
public class StaticProxyDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
ProxySubject proxySubject = new ProxySubject(realSubject);
proxySubject.request();
}
}
输出结果:
ProxySubject: Before handling request.
RealSubject: Handling request.
ProxySubject: After handling request.
优点:
缺点:
动态代理是指在运行时动态生成代理类,而不是在编译时确定。Java提供了两种方式来实现动态代理:基于接口的JDK动态代理和基于类的CGLIB动态代理。
JDK动态代理是基于接口的代理方式,它通过java.lang.reflect.Proxy
类和java.lang.reflect.InvocationHandler
接口来实现。
InvocationHandler
接口,在invoke
方法中定义代理逻辑。Proxy.newProxyInstance
方法创建代理对象。import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 1. 定义接口
interface Subject {
void request();
}
// 2. 实现目标类
class RealSubject implements Subject {
@Override
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 3. 实现InvocationHandler
class DynamicProxyHandler implements InvocationHandler {
private Object target;
public DynamicProxyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("DynamicProxy: Before handling request.");
Object result = method.invoke(target, args);
System.out.println("DynamicProxy: After handling request.");
return result;
}
}
// 4. 创建代理对象
public class JDKDynamicProxyDemo {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
Subject proxySubject = (Subject) Proxy.newProxyInstance(
realSubject.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(),
new DynamicProxyHandler(realSubject)
);
proxySubject.request();
}
}
输出结果:
DynamicProxy: Before handling request.
RealSubject: Handling request.
DynamicProxy: After handling request.
优点:
缺点:
CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以在运行时扩展Java类和实现接口。CGLIB动态代理是基于类的代理方式,它通过继承目标类来生成代理类。
MethodInterceptor
接口,在intercept
方法中定义代理逻辑。Enhancer
类创建代理对象。import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
// 1. 定义目标类
class RealSubject {
public void request() {
System.out.println("RealSubject: Handling request.");
}
}
// 2. 实现MethodInterceptor
class CglibProxyInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("CglibProxy: Before handling request.");
Object result = proxy.invokeSuper(obj, args);
System.out.println("CglibProxy: After handling request.");
return result;
}
}
// 3. 创建代理对象
public class CglibDynamicProxyDemo {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new CglibProxyInterceptor());
RealSubject proxySubject = (RealSubject) enhancer.create();
proxySubject.request();
}
}
输出结果:
CglibProxy: Before handling request.
RealSubject: Handling request.
CglibProxy: After handling request.
优点:
缺点:
远程代理用于在不同的地址空间中代表对象。例如,远程方法调用(RMI)中的存根(Stub)对象就是远程代理的一种实现。
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
// 1. 定义远程接口
interface RemoteSubject extends Remote {
void request() throws RemoteException;
}
// 2. 实现远程对象
class RemoteSubjectImpl extends UnicastRemoteObject implements RemoteSubject {
protected RemoteSubjectImpl() throws RemoteException {
super();
}
@Override
public void request() throws RemoteException {
System.out.println("RemoteSubject: Handling request.");
}
}
// 3. 创建存根对象
public class RemoteProxyDemo {
public static void main(String[] args) {
try {
RemoteSubject remoteSubject = new RemoteSubjectImpl();
// 注册远程对象
java.rmi.Naming.rebind("//localhost/RemoteSubject", remoteSubject);
System.out.println("RemoteSubject bound in registry");
} catch (Exception e) {
e.printStackTrace();
}
}
}
客户端调用:
import java.rmi.Naming;
public class RemoteClient {
public static void main(String[] args) {
try {
RemoteSubject remoteSubject = (RemoteSubject) Naming.lookup("//localhost/RemoteSubject");
remoteSubject.request();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
RemoteSubject: Handling request.
虚拟代理用于根据需要创建开销很大的对象。例如,延迟加载图片或大型文档。
// 1. 定义接口
interface Image {
void display();
}
// 2. 实现目标类
class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
System.out.println("Loading image: " + filename);
}
@Override
public void display() {
System.out.println("Displaying image: " + filename);
}
}
// 3. 实现代理类
class ProxyImage implements Image {
private String filename;
private RealImage realImage;
public ProxyImage(String filename) {
this.filename = filename;
}
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// 4. 客户端调用
public class VirtualProxyDemo {
public static void main(String[] args) {
Image image = new ProxyImage("test.jpg");
// 图片未加载
image.display();
// 图片已加载
image.display();
}
}
输出结果:
Loading image: test.jpg
Displaying image: test.jpg
Displaying image: test.jpg
保护代理用于控制对原始对象的访问权限。例如,权限控制。
// 1. 定义接口
interface SensitiveData {
void access();
}
// 2. 实现目标类
class RealSensitiveData implements SensitiveData {
@Override
public void access() {
System.out.println("Accessing sensitive data.");
}
}
// 3. 实现代理类
class ProtectionProxy implements SensitiveData {
private RealSensitiveData realSensitiveData;
private String userRole;
public ProtectionProxy(String userRole) {
this.userRole = userRole;
}
@Override
public void access() {
if ("admin".equals(userRole)) {
if (realSensitiveData == null) {
realSensitiveData = new RealSensitiveData();
}
realSensitiveData.access();
} else {
System.out.println("Access denied. You do not have the required permissions.");
}
}
}
// 4. 客户端调用
public class ProtectionProxyDemo {
public static void main(String[] args) {
SensitiveData data = new ProtectionProxy("user");
data.access(); // Access denied
data = new ProtectionProxy("admin");
data.access(); // Accessing sensitive data
}
}
输出结果:
Access denied. You do not have the required permissions.
Accessing sensitive data.
智能引用用于在访问对象时执行额外的操作。例如,引用计数、懒加载、日志记录等。
// 1. 定义接口
interface Resource {
void use();
}
// 2. 实现目标类
class RealResource implements Resource {
@Override
public void use() {
System.out.println("Using real resource.");
}
}
// 3. 实现代理类
class SmartReferenceProxy implements Resource {
private RealResource realResource;
private int referenceCount = 0;
@Override
public void use() {
if (realResource == null) {
realResource = new RealResource();
}
realResource.use();
referenceCount++;
System.out.println("Reference count: " + referenceCount);
}
}
// 4. 客户端调用
public class SmartReferenceProxyDemo {
public static void main(String[] args) {
Resource resource = new SmartReferenceProxy();
resource.use();
resource.use();
}
}
输出结果:
Using real resource.
Reference count: 1
Using real resource.
Reference count: 2
代理模式有多种变体,常见的有以下几种:
代理模式可以与其他设计模式结合使用,以实现更复杂的功能。例如:
代理模式是一种非常有用的结构型设计模式,它通过引入代理对象来控制对目标对象的访问。代理模式有多种实现方式,包括静态代理和动态代理(JDK动态代理和CGLIB动态代理)。代理模式在远程代理、虚拟代理、保护代理和智能引用等场景中都有广泛的应用。
通过代理模式,我们可以在不修改目标对象的情况下,增加额外的功能或控制访问。代理模式的灵活性和扩展性使得它在实际开发中非常有用。然而,代理模式也带来了一定的复杂性和性能开销,因此在使用时需要权衡利弊。
希望本文能够帮助你更好地理解和应用代理模式,在实际开发中灵活运用代理模式来解决各种问题。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。