代理模式分为静态代理、动态代理模式,其目的是为某个对象提供间接的访问方式,不去直接访问对象,达到了解耦的作用,以及增强的作用。
静态代理
这是从百度百科摘取下来的
Subject:可以是抽象类或者是接口。
RealSubject:是Subject的实现类,真正的逻辑功能在这个类中完成,也就是被代理类(委托类)。
Proxy:就是代理类,也实现了Subject中的方法,但是不像RealSubject一样实现逻辑,而是增加一些扩展功能,达到增强的作用。通过Proxy类访问RealSubject,客户端与RealSubject起到解耦作用。
下面看看静态代理的示例
//用户表接口(Subject)
public interface UserManager {
//保存用户
void saveUser(User user);
//删除用户
void delUser(User user);
//更新用户
void updUser(User user);
}
//用户实现类(被代理类)
public class RealUserManagerImp implements UserManager {
@Override
public void saveUser(User user) {
System.out.println("被代理类执行了用户保存");
}
@Override
public void delUser(User user) {
System.out.println("被代理类执行了用户删除");
}
@Override
public void updUser(User user) {
System.out.println("被代理类执行了用户更新");
}
}
//用户实现类(代理类)
public class ProxyUserManagerImp implements UserManager {
private UserManager userManager;
public ProxyUserManagerImp(UserManager userManager) {
this.userManager = userManager;
}
@Override
public void saveUser(User user) {
System.out.println("---连接数据库");
System.out.println("---打开事务");
userManager.saveUser(user);
System.out.println("---提交");
System.out.println("----关闭事务");
System.out.println("----关闭数据库连接");
}
@Override
public void delUser(User user) {
System.out.println("---连接数据库");
System.out.println("---打开事务");
userManager.delUser(user);
System.out.println("---提交");
System.out.println("----关闭事务");
System.out.println("----关闭数据库连接");
}
@Override
public void updUser(User user) {
System.out.println("---连接数据库");
System.out.println("---打开事务");
userManager.updUser(user);
System.out.println("---提交");
System.out.println("----关闭事务");
System.out.println("----关闭数据库连接");
}
}
public class ClientDemo {
public static void main(String[] args) {
//其实后来写「装饰模式」的时候,区分装饰跟静态代理两种模式,
//我觉得在静态代理这里,客户端调用代理的时候,不应该传这个具体的RealUserManagerImp实例
//应该在代理类的构造方法中去创建这个被代理类
//达到一种客户端「无感」调用 -- 记2018-12-21
UserManager userManager = new ProxyUserManagerImp(new RealUserManagerImp());
userManager.saveUser(new User());
}
}
通过上面的示例,我们可以看到是一个数据保存的过程。客户端想保存某个用户信息,直接访问代理类的saveUser方法。代理类为被代理类做了数据保存前的操作以及数据保存之后的操作,扩展了保存的功能。
但是静态代理类有个缺点。假设我现在有LogManager,上方的代码得全部敲一遍。一个数据库有20个表呢?是不是就发现就得需要20个代理类?所以就需要动态生成代理类。
下面看示例,UserManager、RealUserManagerImp这两个类原封不动,然后加入下面这个类
//动态代理类
public class ProxyUserManagerHandle implements InvocationHandler {
//目标对象(例如User\Log等等)
private Object targetObject;
//通过Proxy类,动态生成代理类,并且创建代理类实例
public Object newProxyInstance(Object targetObject) {
this.targetObject = targetObject;
//第一个参数为目标对象的类加载器
//第二个参数为目标对象继承的接口
//第三个参数为需要执行哪个handler中invoke的方法
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("---连接数据库");
System.out.println("---打开事务");
method.invoke(targetObject, args);
System.out.println("args:" + args);
System.out.println("---提交");
System.out.println("----关闭事务");
System.out.println("----关闭数据库连接");
return null;
}
}
然后再运行一下客户端
public class ClientDemo {
public static void main(String[] args) {
ProxyUserManagerHandle pumh = new ProxyUserManagerHandle();
UserManager userManagerProxy = (UserManager) pumh.newProxyInstance(new RealUserManagerImp());
userManagerProxy.delUser(new User());
}
}
动态代理与静态代理的区别,前者是在程序运行中的时候创建的,大大减少了应用的代码量,而且jdk在底层创建的时候有一个代理缓存池,动态创建的时候会先去缓存中查找,有就直接返回,没有才创建,这也加大了程序的运行的效率。后者是程序运行前就已经存在的文件。
代理模式到这里就写完了,有很多作者写得比我好,也比我写的更高深,我仅仅是记录我自己现阶段理解的,仅此而已。如果各位读者能够阅读到这句话,希望能留下你们宝贵的意见,或者一些看法,让我能够学习改进一下,谢谢大家。