代理模式分为静态代理、动态代理模式,其目的是为某个对象提供间接的访问方式,不去直接访问对象,达到了解耦的作用,以及增强的作用。

静态代理

代理模式 - 图1

这是从百度百科摘取下来的

Subject:可以是抽象类或者是接口。
RealSubject:是Subject的实现类,真正的逻辑功能在这个类中完成,也就是被代理类(委托类)。
Proxy:就是代理类,也实现了Subject中的方法,但是不像RealSubject一样实现逻辑,而是增加一些扩展功能,达到增强的作用。通过Proxy类访问RealSubject,客户端与RealSubject起到解耦作用。

下面看看静态代理的示例

  1. //用户表接口(Subject)
  2. public interface UserManager {
  3. //保存用户
  4. void saveUser(User user);
  5. //删除用户
  6. void delUser(User user);
  7. //更新用户
  8. void updUser(User user);
  9. }
  1. //用户实现类(被代理类)
  2. public class RealUserManagerImp implements UserManager {
  3. @Override
  4. public void saveUser(User user) {
  5. System.out.println("被代理类执行了用户保存");
  6. }
  7. @Override
  8. public void delUser(User user) {
  9. System.out.println("被代理类执行了用户删除");
  10. }
  11. @Override
  12. public void updUser(User user) {
  13. System.out.println("被代理类执行了用户更新");
  14. }
  15. }
  1. //用户实现类(代理类)
  2. public class ProxyUserManagerImp implements UserManager {
  3. private UserManager userManager;
  4. public ProxyUserManagerImp(UserManager userManager) {
  5. this.userManager = userManager;
  6. }
  7. @Override
  8. public void saveUser(User user) {
  9. System.out.println("---连接数据库");
  10. System.out.println("---打开事务");
  11. userManager.saveUser(user);
  12. System.out.println("---提交");
  13. System.out.println("----关闭事务");
  14. System.out.println("----关闭数据库连接");
  15. }
  16. @Override
  17. public void delUser(User user) {
  18. System.out.println("---连接数据库");
  19. System.out.println("---打开事务");
  20. userManager.delUser(user);
  21. System.out.println("---提交");
  22. System.out.println("----关闭事务");
  23. System.out.println("----关闭数据库连接");
  24. }
  25. @Override
  26. public void updUser(User user) {
  27. System.out.println("---连接数据库");
  28. System.out.println("---打开事务");
  29. userManager.updUser(user);
  30. System.out.println("---提交");
  31. System.out.println("----关闭事务");
  32. System.out.println("----关闭数据库连接");
  33. }
  34. }
  1. public class ClientDemo {
  2. public static void main(String[] args) {
  3. //其实后来写「装饰模式」的时候,区分装饰跟静态代理两种模式,
  4. //我觉得在静态代理这里,客户端调用代理的时候,不应该传这个具体的RealUserManagerImp实例
  5. //应该在代理类的构造方法中去创建这个被代理类
  6. //达到一种客户端「无感」调用 -- 记2018-12-21
  7. UserManager userManager = new ProxyUserManagerImp(new RealUserManagerImp());
  8. userManager.saveUser(new User());
  9. }
  10. }

代理模式 - 图2
通过上面的示例,我们可以看到是一个数据保存的过程。客户端想保存某个用户信息,直接访问代理类的saveUser方法。代理类为被代理类做了数据保存前的操作以及数据保存之后的操作,扩展了保存的功能。
但是静态代理类有个缺点。假设我现在有LogManager,上方的代码得全部敲一遍。一个数据库有20个表呢?是不是就发现就得需要20个代理类?所以就需要动态生成代理类

下面看示例,UserManager、RealUserManagerImp这两个类原封不动,然后加入下面这个类

  1. //动态代理类
  2. public class ProxyUserManagerHandle implements InvocationHandler {
  3. //目标对象(例如User\Log等等)
  4. private Object targetObject;
  5. //通过Proxy类,动态生成代理类,并且创建代理类实例
  6. public Object newProxyInstance(Object targetObject) {
  7. this.targetObject = targetObject;
  8. //第一个参数为目标对象的类加载器
  9. //第二个参数为目标对象继承的接口
  10. //第三个参数为需要执行哪个handler中invoke的方法
  11. return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
  12. targetObject.getClass().getInterfaces(), this);
  13. }
  14. @Override
  15. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  16. System.out.println("---连接数据库");
  17. System.out.println("---打开事务");
  18. method.invoke(targetObject, args);
  19. System.out.println("args:" + args);
  20. System.out.println("---提交");
  21. System.out.println("----关闭事务");
  22. System.out.println("----关闭数据库连接");
  23. return null;
  24. }
  25. }

然后再运行一下客户端

  1. public class ClientDemo {
  2. public static void main(String[] args) {
  3. ProxyUserManagerHandle pumh = new ProxyUserManagerHandle();
  4. UserManager userManagerProxy = (UserManager) pumh.newProxyInstance(new RealUserManagerImp());
  5. userManagerProxy.delUser(new User());
  6. }
  7. }

代理模式 - 图3
动态代理与静态代理的区别前者是在程序运行中的时候创建的,大大减少了应用的代码量,而且jdk在底层创建的时候有一个代理缓存池,动态创建的时候会先去缓存中查找,有就直接返回,没有才创建,这也加大了程序的运行的效率。后者是程序运行前就已经存在的文件。

代理模式到这里就写完了,有很多作者写得比我好,也比我写的更高深,我仅仅是记录我自己现阶段理解的,仅此而已。如果各位读者能够阅读到这句话,希望能留下你们宝贵的意见,或者一些看法,让我能够学习改进一下,谢谢大家。