代理模式

1. 代理模式的定义与特点

代理模式:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问的对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

优点

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用
  • 代理对象可以扩展目标对象的功能
  • 代理模式能将目标对象与客户端分开,在一定程度上降低了系统的耦合度,增加了程序的可扩展性

缺点

  • 代理模式系统设计中类的增加
  • 在客户端和目标对象之间增加了一个代理对象,会造成请求处理速度变慢。
  • 增加了系统的复杂度。

    那么如何解决以上缺点呢?我们可以采用动态代理模式

2. 代理模式的结构与实现

代理是的结构比较简单,主要通过定义一个继承抽象主题的代理来包含真是主题,从而实现对真是主题的访问。

1. 模式的结构

代理模式的主要角色如下:

  • 代理主题类(Subject):通过接口或者抽象类来声明真是主题和代理对象实现业务的方法。
  • 真实主题类(Real Subject):实现了抽象主题中的具体业务,是代理对象所代表的真是对象,是最终要引用的对象。
  • 代理类(Proxy):提供了与真实主题相同的接口,其内部含有对真是主题的引用,它可以访问,控制或者扩展真实主题的功能。

根据代理的创建时期,分为静态代理动态代理

  • 静态代理:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
  • 动态代理:在程序运行时,运用反射机制动态创建而成

2. 模式的实现

2.1 静态代理

静态代理模式的实现如下:

  1. /**
  2. * @author liyuan
  3. * @date 2021年06月08日 16:36
  4. * 抽象主题,结婚代理
  5. */
  6. public interface MarrySubject {
  7. void marring();
  8. }
  9. /**
  10. * @author liyuan
  11. * @date 2021年06月08日 16:36
  12. * 真实主题,真实结婚对象
  13. */
  14. public class RealMarrySubject implements MarrySubject {
  15. @Override
  16. public void marring() {
  17. System.out.println("marring with my wife.");
  18. }
  19. }
  20. /**
  21. * @Author liyuan
  22. * @Description 婚庆公司代理对象
  23. * 代理类,做结婚扩展
  24. **/
  25. public class WeddingCompanyProxy implements MarrySubject{
  26. private RealMarrySubject realSubject;
  27. public WeddingCompanyProxy(RealMarrySubject realSubject) {
  28. this.realSubject = realSubject;
  29. }
  30. /**
  31. * @Author liyuan
  32. * 结婚
  33. **/
  34. public void marring(){
  35. marringBefore();
  36. realSubject.marring();
  37. marringAfter();
  38. }
  39. private void marringBefore(){
  40. System.out.println("结婚之前做婚礼筹备");
  41. }
  42. private void marringAfter(){
  43. System.out.println("结婚之后洞房花烛");
  44. }
  45. }
  46. /**
  47. * @author liyuan
  48. * @date 2021年06月08日 16:43
  49. * 测试类
  50. */
  51. public class RealSubjectTest {
  52. public static void main(String[] args) {
  53. WeddingCompanyProxy proxy = new WeddingCompanyProxy(new RealMarrySubject());
  54. proxy.marring();
  55. }
  56. }

输出的结果如下:

  1. 结婚之前做婚礼筹备
  2. marring with my wife.
  3. 结婚之后洞房花烛

显然,如果要增加真实主题,也必须要增加相应的代理对象才行,这样灵活度不够高,因此我们可以采用动态代理来弥补这种缺点。

2.2 动态代理

动态代理结构如如下:

其代码如下:

/**
 * @author liyuan
 * @date 2021年06月08日 16:36
 * 抽象主题,结婚代理对象
 */
public interface MarrySubject {

    void marring();
}
/**
 * @author liyuan
 * @date 2021年06月08日 16:36
 * 真实对象
 */
public class RealMarrySubject implements MarrySubject {

    private String boy = "boy";

    private String girl = "girl";

    @Override
    public void marring() {

        System.out.println(boy + " and " + girl +" marring");
    }

}
/**
 * @author liyuan
 * @date 2021年06月08日 17:28
 */
public class OtherRealMarrySubject implements MarrySubject{

    private String boy = "boy1";
    private String girl = "girl1";

    @Override
    public void marring() {
        System.out.println(boy + " and " + girl +" marring");
    }
}

/**
 * @author liyuan
 * @date 2021年06月08日 17:05
 * 动态代理类 婚庆公司动态代理object,需要实现InvocationHandler
 */
public class WeddingCompanyProxyHandler implements InvocationHandler {

    private Object object;

    public WeddingCompanyProxyHandler(Object object){
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        marringBefore();
        method.invoke(object, args);
        marringAfter();
        return null;
    }

    private void marringBefore(){
        System.out.println("结婚之前做婚礼筹备");
    }

    private void marringAfter(){
        System.out.println("结婚之后洞房花烛");
    }
}
/**
 * @author liyuan
 * @date 2021年06月08日 17:09
 * 测试类
 */
public class DynamicProxyTest {
    public static void main(String[] args) {
        MarrySubject proxy = new RealMarrySubject();
//        MarrySubject proxy1 = new OtherRealMarrySubject();
        WeddingCompanyProxyHandler proxyHandler = new WeddingCompanyProxyHandler(proxy);
        MarrySubject o = (MarrySubject)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), proxy.getClass().getInterfaces(), proxyHandler);
        o.marring();
    }
}

执行的结果如下:

结婚之前做婚礼筹备
boy and girl marring
结婚之后洞房花烛