代理模式的核心,是在被调用方和调用方之间增加一个中介者的角色,即代理
调用方 ===> 代理 ===> 被调用方
我们实际生活的情况,比如
- 租房中介,租客 ===> 中介 ===> 房东
- 抢票的黄牛,购票 ===> 黄牛 ===> 官方售票
- 菜鸟驿站,购物者 ===> 菜鸟驿站 ===> 快递小哥
编码上的体现:
现在我们有一个用户管理类,其中有添加用户、删除用户两个方法
public interface IUserService {
/**
* 添加用户
*/
void insert();
/**
* 删除用户
*/
void delete();
}
// 实现类
public class UserService implements IUserService{
@Override
public void insert() {
// 添加用户
System.out.println("执行添加用户......");
}
@Override
public void delete() {
// 删除用户
System.out.println("执行删除用户......");
}
}
假如我们需要在方法前后加打印日志的操作呢?
立马就有了解决方案,在方法前后加上打印日志的操作不就行了
public class UserService implements IUserService{
@Override
public void insert() {
System.out.println("添加用户前^_^");
// 添加用户
System.out.println("执行添加用户......");
System.out.println("添加用户后o_o");
}
@Override
public void delete() {
System.out.println("删除用户前^_^");
// 删除用户
System.out.println("执行删除用户");
System.out.println("删除用户后o_o");
}
}
之后,我们又有了新的需求,要加一个事务,或者加一个其他的前置功能呢?
再去修改代码,那么就会降低代码的可读性…
那么这时就有了代理类的登场
public class UserServiceStaticProxy implements IUserService{
private final IUserService userService;
public UserServiceStaticProxy(IUserService userService){
this.userService = userService;
}
@Override
public void insert() {
System.out.println("添加用户开始......");
userService.insert();
System.out.println("添加用户结束......");
}
@Override
public void delete() {
System.out.println("删除用户开始......");
userService.delete();
System.out.println("删除用户结束......");
}
}
代码中,代理类和业务类实现了相同的接口,并且重写了添加、删除用户的方法
在重写的代码中,我们就可以再去额外的操作处理了
public class ProxyClient {
public static void main(String[] args) {
IUserService userService = new UserServiceStaticProxy(new UserService());
userService.insert();
System.out.println();
System.out.println("华丽的分割线---------->");
System.out.println();
userService.delete();
}
}
执行结果返回
添加用户开始…
执行添加用户…
添加用户结束…
华丽的分割线---------->
删除用户开始…
执行删除用户
删除用户结束…
给对象的行为增加辅助功能的解决方案,就是代理模式
这时,我们再有其他的学生管理类、教师管理类需要增加日志,难道都要配置一个代理类吗???
根据上面代理类的命名也可以看出,上面进行的是一个静态代理,与之对应的还有一个动态代理
所谓动态代理,就是在程序运行时,动态的为被代理对象生成代理类,这就需要借助反射的特性了
这就需要使用到了InvocationHandler接口的实现和Proxy类
public class UserServiceDynamicProxy implements InvocationHandler {
private final IUserService userService;
public UserServiceDynamicProxy(IUserService userService){
this.userService = userService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName() + "方法调用前......");
method.invoke(userService, args);
System.out.println(method.getName() + "方法调用后......");
return null;
}
}
public class ProxyClient {
public static void main(String[] args) {
IUserService userService = new UserService();
InvocationHandler userServiceInvocationHandler = new UserServiceDynamicProxy(userService);
IUserService userServiceProxy = (IUserService) Proxy.newProxyInstance(userServiceInvocationHandler.getClass().getClassLoader(), userService.getClass().getInterfaces(), userServiceInvocationHandler);
userServiceProxy.insert();
System.out.println();
userServiceProxy.delete();
}
}
除了JDK的动态代理,还有CGlib的动态代理
那么,代理模式和装饰模式都是把原有的类对象作为成员,放在代理类或者装饰类中去调用,它们有什么区别呢???
从两个方向去区别
对于原有的类来说,装饰模式是“自己人”,是对自身功能的增加;而代理模式是“外人”,增加的功能和自身并无直接关系
另一个方向,代理模式关心的不是结果,是过程;装饰模式关心的是最终的结果