互联网轻量级框架整合之设计模式

反射技术

Java的反射技术能够通过配置类的全限定名、方法和参数完成对象的初始化,甚至反射某些方法,大大的增强了Java的可配置型,这也是Spring IoC的底层原理,Java的反射技术覆盖面很广,包括对象构建、反射方法、注解、参数、接口等等,而这一切都是通过java.lang.reflect.*来完成的

通过反射构建对象

package com.ssm.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 反射服务实现类
 */
public class ReflectServiceImpl{

    /**
     * 向指定名字的人打招呼
     * @param name 人的名字
     */
    public static string sayHello(String name)
    {
        System.out.println( "Hello"+name);
        return string;
    }

    /**
     * 获取ReflectServiceImpl类的实例
     * 通过反射获取无参构造函数创建实例
     * @return 返回ReflectServiceImpl类的实例
     */
    public static ReflectServiceImpl getInstance(){
        ReflectServiceImpl object = null;
        try {
            //通过反射获取类的无参构造函数
            Constructor<ReflectServiceImpl> constructor = ReflectServiceImpl.class.getConstructor();
            //通过构造函数创建实例
            object = constructor.newInstance();
        }catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException| InvocationTargetException e){
            //捕获反射过程中可能抛出的异常
            e.printStackTrace();
        }
        return object;
    }
}

package com.ssm.reflect;

import org.junit.Test;
import static org.junit.Assert.*;

/**
 * ReflectServiceImpl类的测试类,用于测试其功能的正确性。
 */
public class ReflectServiceImplTest {

    /**
     * 测试sayHello方法是否能正确地返回拼接好的字符串。
     * 参数:无
     * 返回值:无
     */
    @Test
    public void testSayHello() {
        ReflectServiceImpl service = ReflectServiceImpl.getInstance();
        String string = ReflectServiceImpl.sayHello("Tom");
        assertEquals("Tom", string); // 验证返回的字符串是否为"HelloTom"
    }

    /**
     * 测试GetInstance方法是否能返回非空的ReflectServiceImpl实例。
     * 参数:无
     * 返回值:无
     */
    @Test
    public void testGetInstance() {
        ReflectServiceImpl service = ReflectServiceImpl.getInstance();
        assertNotNull(service); // 确保返回的实例不为空
    }

    /**
     * 测试GetInstance方法是否每次调用都返回相同的实例。
     * 参数:无
     * 返回值:无
     */
    @Test
    public void testSameInstance() {
        ReflectServiceImpl service1 = ReflectServiceImpl.getInstance();
        ReflectServiceImpl service2 = ReflectServiceImpl.getInstance();
        assertNotSame(service1, service2);
    }
}

package com.ssm.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 这是一个通过反射机制实现的示例服务类,演示了如何通过反射创建实例。
 */
public class ReflectServiceImplII {
    private String name; // 姓名字段

    /**
     * 构造函数,用于初始化对象的name属性。
     *
     * @param name 传入的姓名字符串。
     */
    public ReflectServiceImplII(String name){
        this.name = name;
    }

    /**
     * 静态方法,用于打印问候语。
     *
     * @param name 传入的姓名,将被用于构造问候语。
     */
    public static void sayHello(String name)
    {
        System.out.println( "Hello"+name);
    }

    /**
     * 静态方法,用于通过反射机制创建ReflectServiceImplII的实例。
     *
     * @return 返回通过反射创建的ReflectServiceImplII实例。
     */
    public static ReflectServiceImplII getInstance(){
        ReflectServiceImplII object = null;
        try {
            // 通过反射获取带有String参数的构造函数
            Constructor<ReflectServiceImplII> constructor = ReflectServiceImplII.class.getConstructor(String.class);
            // 使用反射调用构造函数创建实例
            object = constructor.newInstance("Davie yang");
        }catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException| InvocationTargetException e){
            e.printStackTrace();
        }
        return object;
    }
}
package com.ssm.reflect;

import org.junit.Test;
import static org.junit.Assert.*;

public class ReflectServiceImplIITest {

    @Test
    public void testGetInstance() {
        ReflectServiceImplII instance = ReflectServiceImplII.getInstance();
        instance.sayHello("Davie yang");
        assertNotNull(instance);
        assertEquals("HelloDavie yang", instance.sayHello("Davie yang"));
    }
}

反射的优点在于只要配置就可以生成对象,可以解除程序的耦合度,比较灵活,其缺点是运行相对较慢,反射技术在系统架构中的使用如何取舍是关键,Spring IoC技术就广泛的使用了发射

通过反射构建方法



package com.ssm.reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 反射服务实现类,提供反射机制调用方法的功能演示
 */
public class ReflectServiceImplIII {

    /**
     * 向指定名字的人打招呼
     *
     * @param name 人的名字
     * @void 方法没有返回值
     */
    public static void sayHello(String name) {
        System.out.println("Hello" + name);
    }

    /**
     * 通过反射机制调用sayHello方法
     *
     * @return 返回反射调用方法的返回对象,本例中为null,因为sayHello方法没有返回值
     */
    public Object reflectMethod() {
        Object returnObj = null;
        ReflectServiceImplIII target = new ReflectServiceImplIII();
        try {
            // 获取sayHello方法的Method实例,包括其参数类型
            Method method = ReflectServiceImplIII.class.getMethod("sayHello", String.class);

            // 通过Method实例调用sayHello方法,传入参数"小明"  完成反射
            returnObj = method.invoke(target, "小明");
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException |
                 InvocationTargetException e) {
            // 捕获反射调用中可能出现的异常,并打印堆栈信息
            e.printStackTrace();
        }
        return returnObj;
    }
}

实例


package com.ssm.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 反射服务实现类,提供反射机制调用方法的功能演示
 */
public class ReflectServiceImplIII {

    /**
     * 向指定名字的人打招呼
     *
     * @param name 人的名字
     * @void 方法没有返回值
     */
    public static String sayHello(String name) {
        System.out.println("Hello" + name);
        return "Hello"+name;
    }

    /**
     * 通过反射机制调用sayHello方法
     *
     * @return 返回反射调用方法的返回对象,本例中为null,因为sayHello方法没有返回值
     */
    public static Object reflectMethod() {
        ReflectServiceImplIII object  = null;
        String s = null;
        try {
            Constructor<ReflectServiceImplIII> constructor = ReflectServiceImplIII.class.getConstructor();
            object = constructor.newInstance();
            // 获取sayHello方法的Method实例,包括其参数类型
            Method method = object.getClass().getMethod("sayHello", String.class);

            // 通过Method实例调用sayHello方法,传入参数"小明"
            s = (String) method.invoke(object, "小明");
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException |
                 InvocationTargetException|InstantiationException e) {
            // 捕获反射调用中可能出现的异常,并打印堆栈信息
            e.printStackTrace();
        }
        return s;
    }
}
package com.ssm.reflect;

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class ReflectServiceImplIIITest {


    @Test
    public void testReflectMethod() {
        String result = (String) ReflectServiceImplIII.reflectMethod();
        assertEquals("Hello小明", result);
    }
}

对象在反射机制下生成后,反射了方法,如此便可以通过配置来完成对象和方法的反射,从而增强了可配置性和可扩展性,SpringIoC就是一个典型的样例

动态代理模式和责任链模式

代理模式的意义在于生成一个占位(代理对象),来代理真实对象(目标对象),从而控制真实对象的访问,动态代理和责任链无论在Spring还是在MyBatis中都有重要的应用

  • 代理对象的作用是在访问真实对象之前或者之后加入对应的逻辑,或者根据规则控制决定是否使用真实对象,因此代理必须包含两个步骤其一是建立代理对象和真实对象之间的代理关系,其二是实现代理对象的代理逻辑方法;
  • 在Java中有多种动态代理技术,比如JDK、CGLIB、Javassist、ASM等,最常用的是JDK动态代理,它是JDK自带的功能,另一种是CGLIB动态代理,这是第三方技术,在JDK的动态代理中必须使用接口而CGLIB不需要用起来更简便
  • Spring中常用JDK和CGLIB,而MyBatis还是用了Javassist

JDK动态代理

真实对象
package com.ssm.proxy;

public interface HelloWorld {
    public void sayHelloWorld();
}

package com.ssm.proxy.impl;
import com.ssm.proxy.HelloWorld;
public class HelloWorldImpl implements HelloWorld {
    @Override
    public void sayHelloWorld() {
        System.out.println("Hello World!");
    }
}

代理对象

package com.ssm.proxy.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;

/**
 * JDK动态代理示例类,实现InvocationHandler接口。
 * 用于创建一个代理对象,该代理对象可以在调用方法前后添加额外的操作。
 */
public class JDKProxyExample implements InvocationHandler {
    private Object target = null;

    /**
     * 绑定目标对象,返回一个代理对象。
     *
     * @param target 目标对象,将为目标对象创建一个代理。
     * @return 返回代理对象,该对象实现了目标对象的所有接口。
     */
    public Object bind(Object target) {
        this.target = target;
        // 使用JDK动态代理生成一个代理实例
        // newProxyInstance方法的三个参数意义重大,第一个是类的加载器,此处就是target的类加载器,
        // 第二个是目标对象实现的接口,此处就是target实现的所有接口
        // 第三个参数是InvocationHandler的实现类,此处用到this就是JDKProxyExample的实现类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    /**
     * 当调用代理对象的方法时,实际上会调用此方法。
     *
     * @param proxy 代理对象本身。
     * @param method 被调用的方法。
     * @param args 方法调用时传递的参数。
     * @return 方法的返回值。
     * @throws Throwable 如果方法执行抛出异常,则抛出此异常。
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 方法执行前的操作
        System.out.println("before");
        // 调用目标对象的方法,也是通过反射实现的
        Object result = method.invoke(target, args);
        // 方法执行后的操作
        System.out.println("after");
        return result;
    }
}

在JDK动态代理中,要实现代理逻辑类必须实现java.lang.reflect.InvocathinHandler接口;如代码所示,使用bind方法完成第一步即建立代理对象和真实对象的关系;然后实现代理逻辑的方法即invoke()方法

测试代理对象
package com.ssm.proxy;

import com.ssm.proxy.impl.HelloWorldImpl;
import com.ssm.proxy.impl.JDKProxyExample;
import org.junit.Test;

/**
 * JDK动态代理测试类
 */
public class JDKProxyTest {

    /**
     * 测试使用JDK动态代理创建代理对象并调用方法
     */
    @Test
    public void testJDKProxy() {
        // 创建JDK代理示例实例
        JDKProxyExample jdkProxyExample = new JDKProxyExample();
        // 绑定真实对象并生成代理对象
        HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImpl());
        // 通过代理对象调用方法
        proxy.sayHelloWorld();
    }
}

执行结果如下

before
Hello World!
after

CGLIB动态代理

    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>3.3.0</version>
    </dependency>
真实对象
package com.ssm.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 反射服务实现类
 */
public class ReflectServiceImpl{

    /**
     * 向指定名字的人打招呼
     *
     * @param name 人的名字
     * @return
     */
    public String sayHello(String name)
    {
        System.out.println( "Hello"+name);
        return name;
    }

    /**
     * 获取ReflectServiceImpl类的实例
     * 通过反射获取无参构造函数创建实例
     * @return 返回ReflectServiceImpl类的实例
     */
    public static ReflectServiceImpl getInstance(){
        ReflectServiceImpl object = null;
        try {
            //通过反射获取类的无参构造函数
            Constructor<ReflectServiceImpl> constructor = ReflectServiceImpl.class.getConstructor();
            //通过构造函数创建实例
            object = constructor.newInstance();
        }catch (NoSuchMethodException|SecurityException|InstantiationException|IllegalAccessException|IllegalArgumentException| InvocationTargetException e){
            //捕获反射过程中可能抛出的异常
            e.printStackTrace();
        }
        return object;
    }
}
代理对象

package com.ssm.proxy.impl;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Cglib代理示例类,实现了MethodInterceptor接口。
 * 用于通过Cglib动态生成代理对象。
 */
public class CglibProxyExample implements MethodInterceptor {

    /**
     * 获取代理对象。
     * @param cls 要代理的类的Class对象
     * @return 生成的代理对象
     */
    public Object getProxy(Class cls) {
        Enhancer enhancer = new Enhancer(); // 创建Enhancer对象,用于配置代理对象
        enhancer.setSuperclass(cls); // 设置代理对象的父类为cls
        enhancer.setCallback(this); // 设置回调方法为当前对象
        return enhancer.create(); // 创建并返回代理对象
    }

    /**
     * 当调用代理对象的方法时,会执行此方法。
     * @param proxy 代理对象
     * @param method 被调用的方法
     * @param args 方法参数
     * @param methodProxy 方法代理
     * @return 方法返回值
     * @throws Throwable 异常
     */
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy)throws Throwable {
        // 在方法执行前打印信息
        System.out.println("before method " + method.getName());
        Object result = methodProxy.invokeSuper(proxy, args); // CGLIB反射调用真实对象方法
        // 在方法执行后打印信息
        System.out.println("after method " + method.getName());
        return result; // 返回方法结果
    }
}
测试代理对象
package com.ssm.proxy;

import com.ssm.proxy.impl.CglibProxyExample;
import com.ssm.reflect.ReflectServiceImpl;
import org.junit.Test;


/**
 * CGLIB代理测试类
 * 用于测试CGLIB动态代理的功能
 */
public class CGLIBProxyTest {

    /**
     * 测试CGLIB代理方法
     * 通过CglibProxyExample创建ReflectServiceImpl的代理实例,
     * 然后调用代理实例的方法进行测试
     */
    @Test
    public void testCGLIBProxy() {
        // 创建CglibProxyExample实例
        CglibProxyExample cpe = new CglibProxyExample();
        // 通过CglibProxyExample获取ReflectServiceImpl类的代理实例
        ReflectServiceImpl obj = (ReflectServiceImpl) cpe.getProxy(ReflectServiceImpl.class);
        // 调用代理实例的方法,并传入参数"CGLIB"
        obj.sayHello("CGLIB");

    }

}

拦截器

通常动态代理理解起来较为复杂,通常会设计一个拦截器接口供工程师使用,使用者只需要知道拦截器接口的方法、含义和作用即可,无需知道动态代理的实现过程

package com.ssm.interceptor;

/**
 * 描述了拦截器需要实现的接口。
 * 拦截器用于在指定的方法执行前、执行后或环绕执行过程中进行额外的操作。
 */
public interface Interceptor {
    
    /**
     * 在目标方法执行前执行的方法。
     * 
     * @param proxy 代理对象,即被拦截对象的代理。
     * @param target 目标对象,即被拦截的方法所在的对象。
     * @param method 被拦截的方法。
     * @param args 被拦截方法的参数数组。
     * @return 如果返回false,则阻止目标方法的执行;返回true则继续执行目标方法。
     */
    public boolean before(
            Object proxy,
            Object target,
            Method method,
            Object[] args
    );
    
    /**
     * 环绕目标方法执行的方法,可以在方法执行前、执行后、抛出异常时进行操作。
     * 
     * @param proxy 代理对象,即被拦截对象的代理。
     * @param target 目标对象,即被拦截的方法所在的对象。
     * @param method 被拦截的方法。
     * @param args 被拦截方法的参数数组。
     */
    public void around(
            Object proxy,
            Object target,
            Method method,
            Object[] args
    );
    
    /**
     * 在目标方法执行后执行的方法。
     * 
     * @param proxy 代理对象,即被拦截对象的代理。
     * @param target 目标对象,即被拦截的方法所在的对象。
     * @param method 被拦截的方法。
     * @param args 被拦截方法的参数数组。
     */
    public void after(
            Object proxy,
            Object target,
            Method method,
            Object[] args
    );
}


package com.ssm.interceptor.impl;

import com.ssm.interceptor.Interceptor;
import java.lang.reflect.Method;

/**
 * MyInterceptor 类实现了 Interceptor 接口,
 * 用于拦截器的实现,提供 before、after 和 around 方法。
 */
public class MyInterceptor implements Interceptor {

    /**
     * 在目标方法执行前执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     * @return 返回 boolean 值,通常用于决定是否继续执行目标方法
     */
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("before");
        return false; // 默认返回false,表示不继续执行目标方法
    }

    /**
     * 在目标方法执行后执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("after");
    }

    /**
     * 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("around");
    }

}

将这些方法植入到JDK动态代理对应逻辑内

package com.ssm.interceptor.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import com.ssm.interceptor.Interceptor;

/**
 * 使用JDK动态代理实现的拦截器处理类,用于生成目标对象的代理实例。
 */
public class InterceptorJdkProxy implements InvocationHandler {

    private Object target; // 目标对象,即需要被拦截的对象
    private String interceptorClass = null; // 拦截器类的全限定名

    /**
     * 构造函数,初始化目标对象和拦截器类。
     *
     * @param target 目标对象
     * @param interceptorClass 拦截器类的全限定名
     */
    public InterceptorJdkProxy(Object target, String interceptorClass) {
        this.target = target;
        this.interceptorClass = interceptorClass;
    }

    /**
     * 绑定目标对象和拦截器,返回代理对象。
     *
     * @param target 目标对象
     * @param interceptorClass 拦截器类的全限定名
     * @return 代理对象
     */
    public static Object bind(Object target, String interceptorClass){
        // 通过动态代理生成目标对象的代理实例
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
                new InterceptorJdkProxy(target, interceptorClass));
    }

    /**
     * 当调用代理对象的方法时,实际执行此方法。
     *
     * @param proxy 代理对象
     * @param method 被调用的方法
     * @param args 方法参数
     * @return 方法返回值
     * @throws Throwable 方法执行中抛出的异常
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(interceptorClass == null) {
            // 如果设置了拦截器,则先执行拦截器的逻辑
            // 没有设置拦截器,直接调用目标方法
            return method.invoke(target, args);
        }
        Object result = null;
        // 通过反射实例化拦截器
        Interceptor interceptor = (Interceptor)Class.forName(interceptorClass).newInstance();
        // 调用拦截器前置方法
        if(interceptor.before(proxy, target, method, args)) {
            // 如果前置方法返回true,执行目标方法
            result = method.invoke(target, args);
        }else { // 如果前置方法返回false,执行around方法
            interceptor.around(proxy, target, method, args);
        }
        // 调用拦截器后置方法
        interceptor.after(proxy, target, method, args);
        return result;
    }
}


package com.ssm.interceptor;

import com.ssm.interceptor.impl.InterceptorJdkProxy;
import com.ssm.proxy.HelloWorld;
import com.ssm.proxy.impl.HelloWorldImpl;
import org.junit.Test;

/**
 * InterceptorJdkProxy的测试类
 * 用于测试使用JDK动态代理实现的拦截器功能
 */
public class InterceptorJdkProxyTest {

    /**
     * 测试拦截器功能
     * 通过InterceptorJdkProxy为HelloWorldImpl实例绑定拦截器MyInterceptor,
     * 然后调用代理对象的sayHelloWorld方法。
     */
    @Test
    public void testInterceptor() {
        // 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
        HelloWorld proxy = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), "com.ssm.interceptor.impl.MyInterceptor");
        // 调用代理类的方法,会触发拦截器的逻辑
        proxy.sayHelloWorld();
    }
}

执行结果如下

反射方法前逻辑
取代了被代理对象的方法
反射方法后逻辑

Process finished with exit code 0

责任链模式

当一个对象在一个链条上被多个拦截器拦截处理(拦截器也可以选择不拦截处理)时,这样的设计模式就成为责任链模式,它适用于一个对象在多个角色中传递的场景,例如一个审批流,一个工程师请假一周,提交了审批单,需要通过3级审批,每一级都有拦截审批或者修改的审批的动作,这就需要三个拦截器,并在它们之间传递请假申请单; 而如多第一级审批修改了审批单,从而影响了后面的审批,后面的审批都要根据前面的结果进行,这个时候就需要考虑用层层代理来实现,也就是后一步的代理是基于前一步代理基础上生成的

定义三个拦截器,然后还是使用之前的JDK动态代理进行绑定和代理逻辑实现进行测试

package com.ssm.interceptor.impl;

import com.ssm.interceptor.Interceptor;

import java.lang.reflect.Method;

public class MyInterceptorI implements Interceptor {

    /**
     * 在目标方法执行前执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     * @return 返回 boolean 值,通常用于决定是否继续执行目标方法
     */
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorI反射方法前逻辑");
        return false; // 不反射被代理对象原有方法
    }

    /**
     * 在目标方法执行后执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorI反射方法后逻辑");
    }

    /**
     * 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorI取代了被代理对象的方法");
    }

}
package com.ssm.interceptor.impl;

import com.ssm.interceptor.Interceptor;

import java.lang.reflect.Method;

public class MyInterceptorII implements Interceptor {

    /**
     * 在目标方法执行前执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     * @return 返回 boolean 值,通常用于决定是否继续执行目标方法
     */
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorII反射方法前逻辑");
        return false; // 不反射被代理对象原有方法
    }

    /**
     * 在目标方法执行后执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorII反射方法后逻辑");
    }

    /**
     * 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorII取代了被代理对象的方法");
    }

}
package com.ssm.interceptor.impl;

import com.ssm.interceptor.Interceptor;

import java.lang.reflect.Method;

public class MyInterceptorIII implements Interceptor {

    /**
     * 在目标方法执行前执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     * @return 返回 boolean 值,通常用于决定是否继续执行目标方法
     */
    @Override
    public boolean before(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorIII反射方法前逻辑");
        return false; // 不反射被代理对象原有方法
    }

    /**
     * 在目标方法执行后执行的方法。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void after(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorIII反射方法后逻辑");
    }

    /**
     * 在目标方法执行前后执行的方法,可以控制目标方法是否执行。
     * @param proxy 代理对象
     * @param target 目标对象
     * @param method 目标方法
     * @param args 方法参数数组
     */
    @Override
    public void around(Object proxy, Object target, Method method, Object[] args) {
        System.out.println("MyInterceptorIII取代了被代理对象的方法");
    }

}

package com.ssm.interceptor;

import com.ssm.interceptor.impl.InterceptorJdkProxy;
import com.ssm.proxy.HelloWorld;
import com.ssm.proxy.impl.HelloWorldImpl;
import org.junit.Test;

/**
 * InterceptorJdkProxy的测试类
 * 用于测试使用JDK动态代理实现的拦截器功能
 */
public class ChainTest {

    /**
     * 测试拦截器功能
     * 通过InterceptorJdkProxy为HelloWorldImpl实例绑定拦截器MyInterceptor,
     * 然后调用代理对象的sayHelloWorld方法。
     */
    @Test
    public void testInterceptorChain() {
        String packageName = "com.ssm.interceptor.impl.";
        // 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
        HelloWorld proxy1 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), packageName+"MyInterceptorI");
        // 调用代理类的方法,会触发拦截器的逻辑
        proxy1.sayHelloWorld();
        // 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
        HelloWorld proxy2 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), packageName+"MyInterceptorII");
        // 调用代理类的方法,会触发拦截器的逻辑
        proxy2.sayHelloWorld();
        // 使用InterceptorJdkProxy动态生成HelloWorld接口的代理类
        HelloWorld proxy3 = (HelloWorld) InterceptorJdkProxy.bind(new HelloWorldImpl(), packageName+"MyInterceptorIII");
        // 调用代理类的方法,会触发拦截器的逻辑
        proxy3.sayHelloWorld();

    }
}

执行结果如下

MyInterceptorI反射方法前逻辑
MyInterceptorI取代了被代理对象的方法
MyInterceptorI反射方法后逻辑
MyInterceptorII反射方法前逻辑
MyInterceptorII取代了被代理对象的方法
MyInterceptorII反射方法后逻辑
MyInterceptorIII反射方法前逻辑
MyInterceptorIII取代了被代理对象的方法
MyInterceptorIII反射方法后逻辑

Process finished with exit code 0

观察者模式

观察者模式又称为发布订阅模式,是对象的行为模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听被观察者的状态,当被观察这得状态发生了变化,会通知所有观察者自动处理各自的逻辑

package com.ssm.observer;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

public class ProductList extends Observable {
    private List<String> productList = null; //产品列表

    private static ProductList productListInstance = null; //类唯一实例

    /**
     * ProductList的私有构造方法。
     * 由于该方法被设置为私有,外部无法直接通过new关键字创建ProductList的实例。
     * 这种设计通常用于不允许外部直接实例化对象的类,或者该类仅作为工具类存在,不需实例化。
     */
    private ProductList() { // 构造方法私有化,防止外部直接实例化
    }
    /**
     * 获取ProductList的单例实例。
     * 该方法采用懒汉式单例模式,即第一次使用时才创建实例。
     * 实例在创建时会初始化一个空的产品列表,确保后续可以安全使用。
     *
     * @return 返回ProductList的单例实例。
     */
    private static ProductList getInstance() {
        if (productListInstance == null) {
            productListInstance = new ProductList();
            productListInstance.productList = new ArrayList<>();
        }
        return productListInstance;
    }


    /**
     * 向产品列表观察者模式中添加一个观察者。
     * @param observer 要添加的观察者对象,它必须实现Observer接口。
     */
    public void addProductListObserver(Observer observer) {
        this.addObserver(observer);
    }

    /**
     * 向产品列表中添加一个新产品,并通知所有观察者。
     * @param product 要添加到产品列表的新产品名称。
     */
    public void addProduct(String product) {
        productList.add(product); // 将新产品添加到产品列表中
        this.setChanged(); // 标记产品列表为已更改,通知观察者被观察者变化,触发观察者行为
        this.notifyObservers(product); // 通知所有观察者产品列表已更改,传递新产品名称作为更新信息
    }
}


package com.ssm.observer;

import java.util.Observer;
import java.util.Observable;

/**
 * XObserver类实现了Observer接口,用于观察ProductList对象的变化。
 */
public class XObserver implements Observer {

    /**
     * 当被观察的对象状态发生变化时,此方法会被调用。
     *
     * @param o 发生变化的Observable对象,这里被强制转换为ProductList类型。
     * @param product Observable对象状态变化的具体内容,这里被强制转换为String类型。
     */
    @Override
    public void update(Observable o, Object product) {
        ProductList productList = (ProductList)o; // 将Observable对象转换为ProductList类型
        String newProduct = (String)product; // 将变化的内容转换为String类型
        System.out.println("XObserver: " + newProduct); // 打印接收到的产品信息
    }
}


/**
 * YObserver类实现了Observer接口,用于观察ProductList对象的变动。
 */
package com.ssm.observer;

import java.util.Observer;
import java.util.Observable;

public class YObserver implements Observer {

    /**
     * 当被观察的对象发生变动时,此方法会被调用。
     * @param o 发生变动的Observable对象。
     * @param product 观察到的变动的具体内容。
     */
    @Override
    public void update(Observable o, Object product) {
        // 将Observable对象转换为ProductList类型,将变动内容转换为String类型
        ProductList productList = (ProductList)o;
        String newProduct = (String)product;
        // 打印接收到的产品信息
        System.out.println("YObserver: " + newProduct);
    }
}

package com.ssm.observer;

import org.junit.Test;

/**
 * 观察者模式测试类
 */
public class ObserverTest {

    /**
     * 测试观察者模式的功能
     * 无参数
     * 无返回值
     */
    @Test
    public void testObserver(){
        // 获取ProductList的实例
        ProductList observable = ProductList.getInstance();
        // 创建XObserver实例
        XObserver xObserver = new XObserver();
        // 创建YObserver实例
        YObserver yObserver = new YObserver();
        // 添加观察者
        observable.addObserver(xObserver);
        observable.addObserver(yObserver);
        // 添加产品到产品列表,触发观察者的更新
        observable.addProduct("product1");
    }
}


执行测试结果

YObserver: product1
XObserver: product1

Process finished with exit code 0

这也是解决大量if判断的一个好的方式

普通工厂模式和抽象工厂模式

在这里插入图片描述

对于需要初始化一个对象而言,有一个工厂逻辑上存在实际上也存在,只需要满足它的接口规范,便可以通过工厂去初始化(生产)一个新的对象出来,这就是普通工厂的思维

// 定义产品接口
interface Product {
    void produce();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void produce() {
        System.out.println("Producing Concrete Product A...");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void produce() {
        System.out.println("Producing Concrete Product B...");
    }
}

// 工厂类
class ProductFactory {
    /**
     * 根据传入的产品类型字符串返回对应的具体产品实例
     *
     * @param type 产品类型字符串,如"A"或"B"
     * @return 返回对应的具体产品实例
     * @throws IllegalArgumentException 当传入无效的产品类型时抛出异常
     */
    public static Product createProduct(String type) throws IllegalArgumentException {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        } else {
            throw new IllegalArgumentException("Invalid product type: " + type);
        }
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 使用工厂方法创建并生产产品A
        Product productA = ProductFactory.createProduct("A");
        productA.produce();

        // 使用工厂方法创建并生产产品B
        Product productB = ProductFactory.createProduct("B");
        productB.produce();
    }
}

在这个例子中,我们定义了一个产品接口Product以及两个实现了该接口的 concrete products:ConcreteProductA和ConcreteProductB。接着,我们创建了一个ProductFactory工厂类,它提供了一个静态方法createProduct(),根据传入的产品类型字符串返回对应的具体产品实例。客户端代码Client通过调用工厂方法来创建并操作产品,无需直接关心具体产品的创建细节,从而实现了对产品对象的解耦。这就是普通工厂设计模式的应用

在这里插入图片描述

普通工厂思维解决了一类对象的构建问题,但有时候往往类别又很多,而不是一类,因此需要更高度的抽象一层,而这种情况下对于需要初始化对象而言只需要知道一个逻辑上存在的工厂存在,而无需关心真实的工厂有多少种如何区分的怎么找到他,这就是抽象工厂思维

// 定义产品接口
interface Computer {
    void assemble();
}

// 具体产品:MacComputer
class MacComputer implements Computer {
    @Override
    public void assemble() {
        System.out.println("Assembling Mac Computer...");
    }
}

// 具体产品:WindowsComputer
class WindowsComputer implements Computer {
    @Override
    public void assemble() {
        System.out.println("Assembling Windows Computer...");
    }
}

// 抽象工厂接口
interface ComputerFactory {
    Computer createComputer();
}

// 具体工厂:MacFactory
class MacFactory implements ComputerFactory {
    @Override
    public Computer createComputer() {
        return new MacComputer();
    }
}

// 具体工厂:WindowsFactory
class WindowsFactory implements ComputerFactory {
    @Override
    public Computer createComputer() {
        return new WindowsComputer();
    }
}

//抽象工厂
package com.ssm.factory;

public class ABProductFactory implements ComputerFactory{
    @Override
    public Computer createComputer(String productNo) {
        ComputerFactory factory=null;
        if(productNo == "mac"){
            factory= (ComputerFactory) new MacFactory();
        }
        else if(productNo =="windows"){
            factory= (ComputerFactory) new WindowsFactory();
        }
        else if(productNo != null){
            factory= (ComputerFactory) new LinuxFactory();
        }
        return null;
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 使用MacFactory创建并组装Mac电脑
        ABProductFactory abProductFactory = new ABProductFactory();
        ComputerFactory macFactory = (ComputerFactory) abProductFactory.createComputer("mac");
        macFactory.createComputer("mac");

        // 使用WindowsFactory创建并组装Windows电脑
        ComputerFactory windowsFactory = (ComputerFactory) abProductFactory.createComputer("windows");
        windowsFactory.createComputer("windows");
    }
}

建造者模式

建造者模式属于对象的构建模式,可以将一个产品的内部属性与产品的生产过程分开来,从而使一个建造过程生成具有不同内部表象的产品;通过一个配置类对构建对象的步骤和参数进行统筹,然后将信息交给构建器来完成对象的构建,就是该模式的本质

// 定义Car类,表示汽车
class Car {
    private String engine;
    private String transmission;
    private String bodyType;
    private int seats;

    public String getEngine() {
        return engine;
    }

    public String getTransmission() {
        return transmission;
    }

    public String getBodyType() {
        return bodyType;
    }

    public int getSeats() {
        return seats;
    }

    protected void setEngine(String engine) {
        this.engine = engine;
    }

    protected void setTransmission(String transmission) {
        this.transmission = transmission;
    }

    protected void setBodyType(String bodyType) {
        this.bodyType = bodyType;
    }

    protected void setSeats(int seats) {
        this.seats = seats;
    }

    @Override
    public String toString() {
        return "Car{" +
                "engine='" + engine + '\'' +
                ", transmission='" + transmission + '\'' +
                ", bodyType='" + bodyType + '\'' +
                ", seats=" + seats +
                '}';
    }
}

// 定义抽象的CarBuilder接口
interface CarBuilder {
    void setEngine(String engine);
    void setTransmission(String transmission);
    void setBodyType(String bodyType);
    void setSeats(int seats);
    Car build();
}

// 具体的CarBuilder实现:SportsCarBuilder
class SportsCarBuilder implements CarBuilder {
    private Car sportsCar = new Car();

    @Override
    public void setEngine(String engine) {
        sportsCar.setEngine(engine);
    }

    @Override
    public void setTransmission(String transmission) {
        sportsCar.setTransmission(transmission);
    }

    @Override
    public void setBodyType(String bodyType) {
        sportsCar.setBodyType(bodyType);
    }

    @Override
    public void setSeats(int seats) {
        sportsCar.setSeats(seats);
    }

    @Override
    public Car build() {
        return sportsCar;
    }
}

// 具体的CarBuilder实现:SUVBuilder
class SUVBuilder implements CarBuilder {
    private Car suv = new Car();

    @Override
    public void setEngine(String engine) {
        suv.setEngine(engine);
    }

    @Override
    public void setTransmission(String transmission) {
        suv.setTransmission(transmission);
    }

    @Override
    public void setBodyType(String bodyType) {
        suv.setBodyType(bodyType);
    }

    @Override
    public void setSeats(int seats) {
        suv.setSeats(seats);
    }

    @Override
    public Car build() {
        return suv;
    }
}

// 负责协调建造过程的CarDirector类
class CarDirector {
    public Car construct(CarBuilder builder) {
        builder.setEngine("V6");
        builder.setTransmission("Automatic");
        builder.setBodyType("Sports");
        builder.setSeats(4);

        return builder.build();
    }
}

// 主程序,演示如何使用建造者模式构建汽车
public class BuilderPatternDemo {
    public static void main(String[] args) {
        CarDirector director = new CarDirector();

        CarBuilder sportsCarBuilder = new SportsCarBuilder();
        Car sportsCar = director.construct(sportsCarBuilder);
        System.out.println("Built Sports Car: " + sportsCar);

        CarBuilder suvBuilder = new SUVBuilder();
        Car suv = director.construct(suvBuilder);
        System.out.println("Built SUV: " + suv);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/537310.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

(Java)数据结构——图(第七节)Folyd实现多源最短路径

前言 本博客是博主用于复习数据结构以及算法的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 Folyd实现原理 中心点的概念 感觉像是充当一个桥梁的作用 还是这个图 我们常在一些讲解视频中看到&#xff0c;就比如dist&#xff08;-1&#xff09;&#xff0…

石子合并(区间dp)-java

石子合并问题是经典的区间dp问题&#xff0c;我们需要枚举中间端点k的情况从而来推出dp数组的值。 文章目录 前言 一、石子合并问题 二、算法思路 1.问题思路 2.状态递推公式 二、代码如下 代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入数据 3.代码运行结果如下&am…

Java开发面试题分享

目录 1、简述MyISAM和InnoDB的区别 2、简述Hash和B树索引的区别 3、简述MyBatis的实现逻辑 4、#{}和${}的区别 5、简述Mybatis的优缺点 6、当实体类中的属性名和表中的字段名不一样时怎么办&#xff1f; 7、resultType与resultMap的区别 8、如何执行批量插入 9、Mybat…

蓝桥杯-数组切分

问题描述 已知一个长度为 N 的数组: A1,A2,A3,...AN 恰好是1~ N的一个排列。现 在要求你将 4 数组切分成若干个 (最少一个,最多 N 个)连续的子数组,并且 每个子数组中包含的整数恰好可以组成一段连续的自然数。 例如对于 4 1,3,2,4,一共有 5 种切分方法: 1324:每个单独的数显然…

(五)PostgreSQL的管理工具pgAdmin

PostgreSQL的管理工具pgAdmin pgAdmin 是一款流行的开源图形界面管理工具&#xff0c;用于 PostgreSQL 数据库的管理和开发。它提供了一个易于使用的界面&#xff0c;允许用户执行各种数据库任务&#xff0c;如创建和修改数据库对象&#xff08;表、视图、索引等&#xff09;、…

Springboot实现链路追踪功能

前言 在日常开发中&#xff0c;一个业务的实现往往会调用很多个方法&#xff0c;当我们去看日志的时候&#xff0c;各种接口的日志打印出来&#xff0c;看着就头疼&#xff0c;压根没办法去定位&#xff0c;而链路追踪就能很好的帮助我们去查看接口从头至尾依次调用了哪些方法…

UE5 在骨骼动画模型上绘制贴图

参考&#xff1a;Unreal 5.1 - How to paint damage textures and other effects on skeletal meshes 针对模型&#xff0c;在运行状态下通过射线指定一定范围&#xff0c;添加材质效果。 核心思路 通过射线获取命中点&#xff0c;作为材质参数材质中&#xff0c;命中的世界…

护眼台灯品牌哪个好?2024五大护眼台灯排行榜分享

​护眼台灯作为家庭中常见的照明工具&#xff0c;其存在几乎成为了现代生活的标配。家长们往往会为孩子购置一台&#xff0c;供学习和阅读使用&#xff1b;同时&#xff0c;它也是学生和办公人员在夜晚工作学习的必备之物。然而&#xff0c;市面上的一些普通台灯可能存在着种种…

【XR806开发板试用】使用硬件SPI驱动TFT液晶屏显示图片

【开发背景】 在完成开发板呼吸灯效果后&#xff08;【XR806开发板试用】使用PWM模块模拟手机呼吸灯提示功能&#xff09;&#xff0c;考虑到显示界面过于单一&#xff0c;如果想要呈现更多的信息就很困难了&#xff0c;刚好之前买过一个TFT液晶屏&#xff0c;正在某个角落吃灰…

OV证书——提升企业在线身份信誉

简介 在当今的数字化时代&#xff0c;网络安全与用户信任成为企业线上运营的基石&#xff0c;而SSL/TLS证书则是确保网站数据传输安全、提升网站信誉度的关键工具之一。其中&#xff0c;组织验证&#xff08;OV&#xff09;证书作为一种特殊类型的SSL证书&#xff0c;通过深入…

Vivado抓信号——提高效率的工具化生成XDC(Python脚本)

操作目录 一、要抓取信号的txt列表二、操作流程 通常情况下&#xff0c;Vivado上板抓取信号的方法主要有两类&#xff1a; &#xff08;1&#xff09;通过在信号前添加(mark_debug“true”)&#xff0c;综合完之后点击Set Up Debug&#xff0c;将需要抓取的信号添加进去&#x…

linux学习:文件类型、文件操作、系统IO、内存映射

目录 文件类别 文件操作 系统 IO 头文件 打开文件 关闭文件 文件描述符 读写 例子 拷贝文件 偏移量 其他接口 mmap()映射 文件类别 普通文件&#xff08;regular&#xff09;&#xff1a;存在于外部存储器中&#xff0c;用于存储普通数据。目录文件&#xff08;d…

蓝桥杯,,,,,,

辗转相除求最大公约数 #include<iostream> using namespace std;int gcd(int a, int b)//求最大公约数&#xff0c;如果返回值为1&#xff0c;最大公约数只有1&#xff0c;为所求 {return b ? gcd(b, a % b) : a; } int main() {int count 0;for(int i1;i<2020;i)f…

进口PFA容量瓶高纯透明聚四氟乙烯材质耐强酸碱PFA定容瓶

PFA容量瓶&#xff0c;也叫特氟龙容量瓶&#xff0c;是用于配制标准浓度溶液的实验室器皿&#xff0c;是有着细长颈、梨形肚的耐强腐蚀平底塑料瓶&#xff0c;颈上有标线&#xff0c;可直接配置标准溶液和准确稀释溶液以及制备样品溶液。 因其有着不易碎、材质纯净、化学稳定性…

Unity Android后处理AO报错

整体流程&#xff1a; 1.添加AO效果 2.Mode 选择 Multi-scale Volumetric Occlusion 3.保证Project Settings - Player - Other Settings - Rendering - Graphic API 内包含 Vulkan 原因&#xff1a; 1.Post Processing文档&#xff1a;https://docs.unity3d.com/Packages/…

探索点云与KD-Tree配对的方法

比较点云是处理和分析点云数据的关键步骤。然而,由于各个扫描之间固有的差异,无法进行逐点比较。因此,点云分析的第一步也是主要步骤是将点配对以进行有意义的比较。 配对点是区分表面变形和运动分析的关键任务。这个过程不仅为变形分析提供了见解,还使我们能够通过比较不…

如何用 Readwise Reader 定制提示词 AI 自动辅助处理信息?

抵御「信息过载」&#xff0c;你需要这样的利器。 痛点 知识工作者的痛点是非常明显的——如果你是一名老师、学生&#xff0c;或是平时需要跟许多资料打交道的人&#xff0c;想必你会经历过信息过载。 信息过载有时候不仅是数量问题&#xff0c;还是一个类型问题。很多不同的信…

【话题】AI技术创业有那些机会,简单探讨下

大家好&#xff0c;我是全栈小5&#xff0c;欢迎阅读小5的系列文章&#xff0c;这是《话题》系列文章 目录 背景机会一、引言二、AI技术的创业机遇1.智能服务行业的兴起2.数据驱动的业务模式创新3.AI与产业融合的创新发展 三、AI技术创业的挑战1.技术门槛高2.法规政策的不确定性…

奎芯科技:智能时代的芯片上游企业如何突破?

半导体IP&#xff08;Intellectual Property&#xff0c;知识产权&#xff09;&#xff0c;通常也称作IP核&#xff08;IP core&#xff09;&#xff0c;指芯片设计中预先设计、验证好的功能模块&#xff0c;主要服务于芯片设计&#xff0c;因部分通用功能模块在芯片中被反复使…

03-JAVA设计模式-享元模式

享元模式 什么是享元模式 享元模式&#xff08;Flyweight Pattern&#xff09;是一种对象结构型设计模式&#xff0c;用于减少创建对象的数量&#xff0c;以减少内存占用和提高系统性能。它通过共享已经存在的对象来避免创建大量相似的对象&#xff0c;从而降低内存消耗。 在…