欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

代理设计模式

最编程 2024-10-16 12:40:16
...
1. 场景设定和问题复现

   1.准备项目

       pom.xml

<dependency>

    <groupId>org.junit.jupiter</groupId>

    <artifactId>junit-jupiter-api</artifactId>

    <version>5.3.1</version>

    <scope>test</scope>

</dependency>

   2. 声明功能接口

/**

 * 功能接口

 */

  public interface GongNeng {

    //吃饭

    void chifan();

    //谈小目标

    void tanxiaomb();

}

3.声明老总目标类实现功能接口

/**

 * 老总:目标对象类,实现功能接口

 */

  public class LaoZong implements GongNeng {

    @Override

    public void chifan() {

        //核心功能

        System.out.println("老总吃饭...");

    }

  

    @Override

    public void tanxiaomb() {

        //核心功能

        System.out.println("老总谈一个亿的小目标...");

    }

}

 

4.声明带预约和联系方式附加功能实现

   新需求: 需要在每个方法中,添加控制台输出,输出预约和输出留个联系方式,方便下次联系!

/**

 * 老总:目标对象类

 * 需要在每个方法中,添加控制台输出,输出预约和输出留个联系方式,方便下次联系!

 */

  public class LaoZong implements GongNeng {

    @Override

    public void chifan() {

        System.out.println("预约....");

        //核心功能

        System.out.println("老总吃饭...");

        System.out.println("留个联系方式,方便下次联系....");

    }

  

    @Override

    public void tanxiaomb() {

        System.out.println("预约....");

        //核心功能

        System.out.println("老总谈一个亿的小目标...");

        System.out.println("留个联系方式,方便下次联系....");

    }

}

  

5.代码问题分析

1. 代码缺陷

    - 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力

    - 附加功能代码重复,分散在各个业务功能方法中!冗余,且不方便统一维护!

2. 解决思路

      核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。

      将重复的代码统一提取,并且[[动态插入]]到每个业务方法!

3. 技术困难

    解决问题的困难:提取重复附加功能代码到一个类中,可以实现

    但是如何将代码插入到各个方法中,我们不会,我们需要引用新技术!!!

6.解决技术代理模式

   1. 代理模式

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

  2. 无代理场景

  3. 有代理场景

   4. 生活中的代理

- 广告商找大明星拍广告需要经过经纪人

- 合作伙伴找大老板谈合作要约见面时间需要经过秘书

- 房产中介是买卖双方的代理

- 太监是大臣和皇上之间的代理

  5. 相关术语

- 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。(中介)

   动词:指做代理这个动作,或这项工作

   名词:扮演代理这个角色的类、对象、方法

- 目标:**被代理**“套用”了核心逻辑代码的类、对象、方法。(房东)

代理在开发中实现的方式具体有两种:静态代理,[动态代理技术]

  6.静态代理实现

     1. 主动创建代理类

/**

 * 秘书:静态代理类

 */

  public class XiaoMi implements GongNeng{

    //将被代理的目标对象:老总

    LaoZong laoZong;

  

    public XiaoMi(LaoZong laoZong) {

        this.laoZong = laoZong;

    }

  

    @Override

    public void chifan() {

        //附加功能由代理类中的代理方法来实现:核心业务前执行的操作

        System.out.println("预约....");

        //调用目标对象老总的吃饭方法

        laoZong.chifan();

        //附加功能由代理类中的代理方法来实现:核心业务后执行的操作

        System.out.println("留个联系方式,方便下次联系....");

    }

  

    @Override

    public void tanxiaomb() {

        //附加

        System.out.println("预约....");

        laoZong.tanxiaomb();

        //附加

        System.out.println("留个联系方式,方便下次联系....");

    }

}

  测试代码

@Test

  public void  testStaticProxy(){

    //创建老总对象:马云

    LaoZong yunyun=new LaoZong();

    //创建云云的秘书

    XiaoMi xm=new XiaoMi(yunyun);

    //吃饭

    xm.chifan();

    System.out.println("--------------");

    xm.tanxiaomb();

}

    静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代码,日志功能还是分散的,没有统一管理。

提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理类来实现。这就需要使用动态代理技术了。

7.动态代理

   1. 动态代理技术分类

动态代理是一种在运行时动态生成代理对象的技术。它是一种设计模式,用于在不修改原始对象的情况下,通过代理对象来间接访问原始对象,并在访问前后执行额外的操作。

JDK动态代理:JDK原生的实现方式,需要被代理的目标类必须实现接口!他会根据目标类的接口动态生成一个代理对象!代理对象和目对象有标相同的接口!(拜把子)

cglib:通过继承被代理的目标类实现代理,所以不需要目标类实现接口!(认干爹)

   2.基于jdk代理技术实现
  1. 声明功能接口
/**

 * 功能接口

 */

  public interface GongNeng {

    //吃饭

    void chifan();

    //谈小目标

    void tanxiaomb();

}

    2.声明老总目标类实现功能接口

/**

 * 老总:目标对象类,实现功能接口

 */

  public class LaoZong implements GongNeng {

    @Override

    public void chifan() {

        //核心功能

        System.out.println("老总吃饭...");

    }

  

    @Override

    public void tanxiaomb() {

        //核心功能

        System.out.println("老总谈一个亿的小目标...");

    }

}

  

       3.定义jdk动态代理工厂类,生成动态代理对象和目标对象实现同一个接口,并调用代理方法             invoke()

/**

 * jdk动态代理工厂类,生成小秘动态代理对象

 */

  public class JdkProxyHandler implements InvocationHandler {

    //代理的目标对象

    LaoZong laoZong;

  

    public JdkProxyHandler(LaoZong laoZong) {

        this.laoZong = laoZong;

    }

  

    /**

     * invoke()设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法

     * proxy:代理对象

     * method:代理对象需要实现的方法,即其中需要重写的方法

     * argsmethod所对应方法的参数

     */

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("预约....");

        //调用目标对象的方法

        Object obj=method.invoke(laoZong,args);

        System.out.println("留下联系方式,方便下次联系....");

        return obj;

    }

}

     4. 测试代码

/**

 * JDK动态代理

 */

  @Test

  public void testJdkProxy(){

    //创建老总对象

    LaoZong yunyun=new LaoZong();

    /**

     * 创建代理对象,通过jdk动态代理生成代理对象的方法

     * Proxy.newProxyInstance():创建一个代理实例

     * 其中有三个参数:

     * 1classLoader:加载动态生成的代理类的类加载器

     * 2interfaces:目标对象实现的所有接口的class对象所组成的数组

     * 3invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法

     */

    GongNeng xm=(GongNeng)Proxy.newProxyInstance(TestProxy.class.getClassLoader(),new Class[]{GongNeng.class},new JdkProxyHandler(yunyun));

    //通过代理对象调用目标对象的方法,从而扩展附加功能

    xm.chifan();

    System.out.println("--------------");

    xm.tanxiaomb();

}

 

3. 基于cglib代理技术,生成动态代理对象

  1.引入cglib坐标

<dependency>

    <groupId>cglib</groupId>

    <artifactId>cglib</artifactId>

    <version>3.3.0</version>

</dependency>

2.定义目标对象的类 (不要实现接口)

/**

 * 老总:目标对象类

 */

  public class LaoZong {

    public void chifan() {

        //核心功能

        System.out.println("老总吃饭...");

    }

    public void tanxiaomb() {

        //核心功能

        System.out.println("老总谈一个亿的小目标...");

    }

}

3.定义cglib动态代理工厂类,生成动态代理对象,是目标对象的子类。

并调用代理方法invoke

/**

 * cglib动态代理工厂类,生成日志动态代理对象

 */

  public class