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

反射技术

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方法是否能正确地返回拼接好的字符串。* 参数:无* 返回值:无*/@Testpublic void testSayHello() {ReflectServiceImpl service = ReflectServiceImpl.getInstance();String string = ReflectServiceImpl.sayHello("Tom");assertEquals("Tom", string); // 验证返回的字符串是否为"HelloTom"}/*** 测试GetInstance方法是否能返回非空的ReflectServiceImpl实例。* 参数:无* 返回值:无*/@Testpublic void testGetInstance() {ReflectServiceImpl service = ReflectServiceImpl.getInstance();assertNotNull(service); // 确保返回的实例不为空}/*** 测试GetInstance方法是否每次调用都返回相同的实例。* 参数:无* 返回值:无*/@Testpublic 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 {@Testpublic 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 {@Testpublic 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 {@Overridepublic 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 如果方法执行抛出异常,则抛出此异常。*/@Overridepublic 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动态代理创建代理对象并调用方法*/@Testpublic 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); // 设置代理对象的父类为clsenhancer.setCallback(this); // 设置回调方法为当前对象return enhancer.create(); // 创建并返回代理对象}/*** 当调用代理对象的方法时,会执行此方法。* @param proxy 代理对象* @param method 被调用的方法* @param args 方法参数* @param methodProxy 方法代理* @return 方法返回值* @throws Throwable 异常*/@Overridepublic 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的代理实例,* 然后调用代理实例的方法进行测试*/@Testpublic 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 值,通常用于决定是否继续执行目标方法*/@Overridepublic 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 方法参数数组*/@Overridepublic void after(Object proxy, Object target, Method method, Object[] args) {System.out.println("after");}/*** 在目标方法执行前后执行的方法,可以控制目标方法是否执行。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic 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方法。*/@Testpublic 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 值,通常用于决定是否继续执行目标方法*/@Overridepublic boolean before(Object proxy, Object target, Method method, Object[] args) {System.out.println("MyInterceptorI反射方法前逻辑");return false; // 不反射被代理对象原有方法}/*** 在目标方法执行后执行的方法。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic void after(Object proxy, Object target, Method method, Object[] args) {System.out.println("MyInterceptorI反射方法后逻辑");}/*** 在目标方法执行前后执行的方法,可以控制目标方法是否执行。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic 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 值,通常用于决定是否继续执行目标方法*/@Overridepublic boolean before(Object proxy, Object target, Method method, Object[] args) {System.out.println("MyInterceptorII反射方法前逻辑");return false; // 不反射被代理对象原有方法}/*** 在目标方法执行后执行的方法。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic void after(Object proxy, Object target, Method method, Object[] args) {System.out.println("MyInterceptorII反射方法后逻辑");}/*** 在目标方法执行前后执行的方法,可以控制目标方法是否执行。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic 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 值,通常用于决定是否继续执行目标方法*/@Overridepublic boolean before(Object proxy, Object target, Method method, Object[] args) {System.out.println("MyInterceptorIII反射方法前逻辑");return false; // 不反射被代理对象原有方法}/*** 在目标方法执行后执行的方法。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic void after(Object proxy, Object target, Method method, Object[] args) {System.out.println("MyInterceptorIII反射方法后逻辑");}/*** 在目标方法执行前后执行的方法,可以控制目标方法是否执行。* @param proxy 代理对象* @param target 目标对象* @param method 目标方法* @param args 方法参数数组*/@Overridepublic 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方法。*/@Testpublic 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类型。*/@Overridepublic 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 观察到的变动的具体内容。*/@Overridepublic 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 {/*** 测试观察者模式的功能* 无参数* 无返回值*/@Testpublic 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: product1Process finished with exit code 0

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

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

在这里插入图片描述

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

// 定义产品接口
interface Product {void produce();
}// 具体产品A
class ConcreteProductA implements Product {@Overridepublic void produce() {System.out.println("Producing Concrete Product A...");}
}// 具体产品B
class ConcreteProductB implements Product {@Overridepublic 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) {// 使用工厂方法创建并生产产品AProduct productA = ProductFactory.createProduct("A");productA.produce();// 使用工厂方法创建并生产产品BProduct productB = ProductFactory.createProduct("B");productB.produce();}
}

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

在这里插入图片描述

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

// 定义产品接口
interface Computer {void assemble();
}// 具体产品:MacComputer
class MacComputer implements Computer {@Overridepublic void assemble() {System.out.println("Assembling Mac Computer...");}
}// 具体产品:WindowsComputer
class WindowsComputer implements Computer {@Overridepublic void assemble() {System.out.println("Assembling Windows Computer...");}
}// 抽象工厂接口
interface ComputerFactory {Computer createComputer();
}// 具体工厂:MacFactory
class MacFactory implements ComputerFactory {@Overridepublic Computer createComputer() {return new MacComputer();}
}// 具体工厂:WindowsFactory
class WindowsFactory implements ComputerFactory {@Overridepublic Computer createComputer() {return new WindowsComputer();}
}//抽象工厂
package com.ssm.factory;public class ABProductFactory implements ComputerFactory{@Overridepublic 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;}@Overridepublic 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();@Overridepublic void setEngine(String engine) {sportsCar.setEngine(engine);}@Overridepublic void setTransmission(String transmission) {sportsCar.setTransmission(transmission);}@Overridepublic void setBodyType(String bodyType) {sportsCar.setBodyType(bodyType);}@Overridepublic void setSeats(int seats) {sportsCar.setSeats(seats);}@Overridepublic Car build() {return sportsCar;}
}// 具体的CarBuilder实现:SUVBuilder
class SUVBuilder implements CarBuilder {private Car suv = new Car();@Overridepublic void setEngine(String engine) {suv.setEngine(engine);}@Overridepublic void setTransmission(String transmission) {suv.setTransmission(transmission);}@Overridepublic void setBodyType(String bodyType) {suv.setBodyType(bodyType);}@Overridepublic void setSeats(int seats) {suv.setSeats(seats);}@Overridepublic 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);}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript 中什么应用场景下必须用 map 而不是对象来实现功能

前言 很多情况下&#xff0c;能用 map 实现的功能用对象也可以实现&#xff0c;都是基于键值对&#xff0c;但是在一些情况下&#xff0c;必须要使用 map 才可以。 必须用 map 而不是 object 的情况 键的类型不限&#xff1a;普通对象的键总是被转换为字符串或者 Symbols&a…

C#简单工厂模式的实现

using System.Diagnostics.Metrics; using System.Runtime.InteropServices; using static 手写工厂模式.Program;namespace 手写工厂模式 {internal class Program{public interface eats {void eat();}//定义了一个接口public class rice : eats{public void eat() {Console.…

Qt快速入门(Opencv小案例之人脸识别)

Qt快速入门&#xff08;Opencv小案例之人脸识别&#xff09; 编译出错记录 背景 因为主要使用qt&#xff0c;并且官网下载的win版本的编译好的opencv默认是vc的&#xff0c;所以我们需要自己下载opencv的源码使用mingw自行编译&#xff0c;我直接使用的vscode。 报错 报错…

【JavaWeb】Day43.MySQL概述——索引

介绍 索引(index)&#xff1a;是帮助数据库高效获取数据的数据结构 。简单来讲&#xff0c;就是使用索引可以提高查询的效率。 优点&#xff1a; 1. 提高数据查询的效率&#xff0c;降低数据库的IO成本。 2. 通过索引列对数据进行排序&#xff0c;降低数据排序的成本&#…

C++系列-C++前言

什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序&#xff0c;对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要高度的抽象和建模时&#xff0c;C语言则不合适&#xff0c;为了解决软件危机&#xff0c;20世纪80年代&#xff0c;计算机界提出…

Python 编程 深入了解内存管理机制、深拷贝与浅拷贝

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、对象和引用、内存管理机制 Python 中的一切都是对象&#xff0c;包括数字、字符串、列表和函数等。为了简化内存管理并提高效率&#xff0c;Python 采用了统一的对象模型。在这个模型中&#xff0c…

【考研数学】看张宇的书,高效自学攻略

张宇老师的课程&#xff0c;我建议还是认真听一下 因为张宇老师视频课并不是照本宣科的读讲义&#xff0c;他是真的有自己的教学方法 讲义上的概念&#xff0c;老师自己会在A4纸上带大家过一遍&#xff0c;并且遇到关键的知识点&#xff0c;老师会强调 张宇老师还会帮我们记…

[C语言][数据结构][链表] 双链表的从零实现!

目录 零.必备知识 0.1 一级指针 && 二级指针 0.2 双链表节点的成员列表 a. 数据 b. 后驱指针 c. 前驱指针 0.3 动态内存空间的开辟 一. 双链表的实现与销毁 1.1 节点的定义 1.2 双向链表的初始化 && 创建新节点 1.3 尾插 1.4 头插 1.5 尾删 1.6 头删 1…

MySQL8.0.36-社区版:错误日志(2)

mysql有个错误日志&#xff0c;是专门记录错误信息的&#xff0c;这个功能默认是开启的 一般都是在/var/log/mysqld.log 日志中存放 1.错误日志的位置 首先我们使用命令去查看一下&#xff0c;这个错误日志文件究竟在哪 进入到mysql中&#xff0c;使用命令 show variables…

二叉树遍历(前序创建|中序遍历)

牛客题目链接 目录 1.解题思路 1.1中序遍历打印 ​1.2前序创建二叉树 1.3注意点 博主这里用的是java实现 随手记一个知识: hasNext读取到空格或者换行符会结束 hasNextLine读取到换行符才会结束&#xff08;空格不会退出&#xff09; 为什么要强调这个呢&#xff1f; …

Vivado Design Suite中的增量实现和增量模式

Vivado Incremental&#xff08;增量&#xff09;是Xilinx FPGA设计工具中的一种功能&#xff0c;它允许对设计的一部分进行修改和重新编译&#xff0c;而不需要对整个设计进行重新编译。这种增量式的方法可以显著减少编译时间&#xff0c;特别是在进行小的修改或迭代开发时。 …

std::stringstream

std::stringstream 是 C 标准库中的一个类&#xff0c;用于对字符串进行输入输出操作&#xff0c;类似于文件流&#xff08;std::ifstream 和 std::ofstream&#xff09;。它允许你像使用 std::cin 和 std::cout 一样使用字符串。 std::stringstream 可以将字符串作为输入源&am…

ThreadPoolExecutor线程池解析

ThreadPoolExecutor线程池解析 一、ThreadPoolExecutor常见参数 jdk中Executors提供了几种常用的线程池&#xff0c;底层都是ThreadPoolExecutor。 public ThreadPoolExecutor(int corePoolSize,//核心线程数int maximumPoolSize,// 最大线程数long keepAliveTime,//非核心线程…

大数据产品有哪些分类?各类里知名大数据产品都有哪些?

随着互联网技术的持续进步和全球数字化转型的推进&#xff0c;我们正处于一个数据爆炸的时代。在这样的大背景下&#xff0c;大数据已经逐渐崭露头角&#xff0c;成为了推动各行各业发展的关键因素和核心资源。大数据不仅仅是指数据的规模巨大&#xff0c;更重要的是它蕴含的价…

量子信息产业生态研究(一):关于《量子技术公司营销指南(2023)》的讨论

写在前面。量子行业媒体量子内参&#xff08;Quantum Insider&#xff09;编制的《量子技术公司营销指南》是一本实用的英文手册&#xff0c;它旨在帮助量子科技公司建立有效的营销策略&#xff0c;同时了解如何将自己定位成各自的行业专家。本文对这篇指南的主要内容进行了翻译…

ubuntu上安装截图工具-Flameshot及其使用步骤说明

Flameshot 火焰截图-推荐 安装命令&#xff1a; sudo apt install flameshot 操作方式&#xff1a; 1&#xff09;打开 2&#xff09;右上角弹窗 3&#xff09;点击后弹出 选择进行截图 4&#xff09;截图后再选择分享 5&#xff09;再重新选择区域&#xff0c;出现编辑…

【蓝桥杯】2024年第15届真题题目

试题 A: 握手问题 本题总分&#xff1a; 5 分 【问题描述】 小蓝组织了一场算法交流会议&#xff0c;总共有 50 人参加了本次会议。在会议上&#xff0c; 大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进 行一次握手&#xff08;且仅有一次&a…

CMD 汉字乱码处理

windows 11 cmd汉字乱码问题处理 一 查看CMD编码 win R 输入 cmd 输入 chcp 查看回显信息 “936”代表的意思就是 GBK (汉字内码扩展规范)&#xff0c;通常情况下GBK也是cmd的默认编码。 解决乱码需要把编码改为 utf-8 二 临时修改 在 终端中输入 chcp 65001 三 永久修改…

蓝桥杯嵌入式第十五届省赛真题题目

蓝桥杯昨天也考完了&#xff0c;大家可以看看题目 客观题题目 程序题题目

【Python函数和类4/6】递归与匿名函数

目录 目标 匿名函数 多个形参 匿名函数的局限性 递归 语言例子 数学例子 递归的实现 递归代码 练习 总结 目标 在之前的博客中&#xff0c;我们学习了定义函数、调用函数以及设置函数的参数。在今天&#xff0c;我们会补充函数的两个常见的知识点&#xff0c;一个是匿…