代理模式是在不改变原对象基础上,通过代理对象控制访问并添加额外操作,以销售代表和助理为例,助理作为代理对象,处理邮件、数据等琐碎工作,使销售代表能专注于与客户面对面交流推销,代理模式让原对象功能得以扩展,同时保持其对外接口的透明性。
定义
代理模式提供了一种在不改变原有对象的情况下,为另一个对象提供一种代理或占位符的方式,代理对象可以控制对原有对象的访问,并可以在访问过程中添加额外的操作,例如记录日志、进行权限验证等。
举一个业务中形象的例子来说明代理模式,假设你是一家公司的销售代表,你负责与客户沟通并推销公司的产品,为了更好地与客户沟通,公司决定为你聘请一位助理,这位助理可以帮你处理一些繁琐的工作,比如回复客户的邮件、整理销售数据等,这样,你就可以专注于与客户进行面对面的交流和推销。在这个例子中,助理就是代理对象,它帮助你处理了一些琐碎的工作,让你能够专注于销售工作,同时,你仍然可以直接与客户进行沟通,并不会改变原有的销售代表角色。
代码案例
下面是一个反例,说明了未使用代理模式时的代码结构,其中客户端直接调用一个服务类的方法,没有任何代理在中间进行拦截或添加额外功能。
首先,我们定义一个服务接口Service
和它的实现类RealService
,如下代码:
// 服务接口
public interface Service {
void performAction();
}
// 真实的服务实现类
public class RealService implements Service {
@Override
public void performAction() {
System.out.println("RealService is performing an action.");
}
}
接下来,我们写一个客户端类Client
,它直接实例化RealService
并调用其方法,如下代码:
// 客户端类,直接调用RealService
public class Client {
public static void main(String[] args) {
// 客户端直接创建RealService的实例并调用其方法
Service service = new RealService();
service.performAction(); // 输出: RealService is performing an action.
}
}
在这个例子中,没有使用代理模式,当客户端需要执行某个操作时,它直接创建RealService
的实例并调用其performAction()
方法,输出结果如下:
RealService is performing an action.
假设,现在我们想要在调用服务方法之前添加一些前置操作,比如日志记录或安全检查,由于我们没有使用代理模式,我们不得不在RealService
类中添加这些逻辑,这可能会破坏类的单一职责原则,并且不易于维护和扩展,而如果我们使用了代理模式,就可以在不修改原有服务类的情况下,通过代理类来添加这些额外的功能。
下面是一个使用代理模式的正例代码,我们引入一个代理类,该类实现与服务类相同的接口,并在其内部持有一个对服务类实例的引用,代理类可以在调用服务类的方法之前或之后执行额外的操作,如日志记录、权限检查等。
首先,我们定义一个服务接口Service
和它的实现类RealService
,如下代码:
// 服务接口
public interface Service {
void performAction();
}
// 真实的服务实现类
public class RealService implements Service {
@Override
public void performAction() {
System.out.println("RealService is performing an action.");
}
}
然后,我们创建一个代理类ServiceProxy
,它同样实现了Service
接口,并持有一个RealService
的引用,如下代码:
// 代理类,实现了Service接口并持有RealService的引用
public class ServiceProxy implements Service {
private Service realService; // 持有真实服务类的引用
public ServiceProxy(Service realService) {
this.realService = realService;
}
@Override
public void performAction() {
System.out.println("Proxy: Preparing to perform action."); // 前置操作
realService.performAction(); // 调用真实服务类的方法
System.out.println("Proxy: Action has been performed."); // 后置操作
}
}
最后,我们写一个客户端类Client
,它使用代理类来间接调用真实的服务类,如下代码:
// 客户端类,使用代理来调用服务
public class Client {
public static void main(String[] args) {
// 创建真实服务类的实例
Service realService = new RealService();
// 创建代理类的实例,并将真实服务类的实例传入
Service proxyService = new ServiceProxy(realService);
// 通过代理类调用方法
proxyService.performAction();
// 输出结果将包括代理类的前置和后置操作信息
}
}
输出结果如下:
Proxy: Preparing to perform action.
RealService is performing an action.
Proxy: Action has been performed.
在这个例子中,客户端通过代理类ServiceProxy
来调用服务,代理类在调用真实服务类的方法之前和之后执行了额外的操作,这种方式允许我们在不修改原有服务类的情况下增加新的功能或控制流程。
本章节拓展知识点:
在Spring中AOP的实现以及事务管理也都是基于代理模式实现的。Spring AOP允许开发者定义横切关注点,这些关注点可以在不修改原有代码的情况下,对程序进行增强,它通过使用代理对象,在目标方法执行前后或出现异常时,织入额外的逻辑,如日志记录、事务管理、安全控制等;Spring中的事务管理会为目标对象创建一个代理对象,这个代理对象会在目标方法执行时开启事务,并在方法执行完成后提交或回滚事务,通过这种方式,Spring实现了声明式事务管理,使得开发者可以专注于业务逻辑的开发,而无需关心事务的细节。
核心总结
代理模式是一种常用的设计模式,它通过引入代理对象来控制对目标对象的访问,增加额外的功能或控制,其优点主要在于:能够在不修改原有代码的基础上增强功能,实现对真实对象的保护和隐藏;提高系统的灵活性和可扩展性,降低耦合度。其缺点主要在于:会增加系统的复杂性和额外的开销,因为需要创建和维护代理类;同时,如果过度使用代理模式,可能会导致系统结构变得复杂和难以理解。
本章节拓展知识点:
代理模式通常会和装饰器模式搞混淆,这两种设计模式在结构上有一定的相似性,因为它们都涉及到一个对象包装另一个对象,并在调用被包装对象的方法时添加一些额外的逻辑。
代理模式的主要目的是控制对另一个对象的访问,它可以添加一些前置或后置的处理逻辑,比如权限检查、日志记录等;;;而装饰器模式的主要目的是动态地给一个对象添加额外的职责或功能,它通过在调用原始对象的方法之前或之后执行一些操作来实现这一点。
尽管两者有一些相似之处,但它们的目的和用法是不同的,代理模式更多地关注于控制访问,而装饰器模式则更多地关注于动态地添加功能。