目录
- 单例模式
- 装饰器模式
- 适配器模式
- 工厂模式
- 观察者模式
- 代理模式
- 命令模式
单例模式
装饰器模式
适配器模式
工厂模式
观察者模式
代理模式
使用代理对象来代替对真实对象的访问,这样就可以在不修改原目标对象的前提下,扩展目标对象的功能,提供额外的功能操作。
例子:下面将通过多种方式去增强 send
方法。
public interface SmsService {
String send(String message);
}
public class SmsServiceImpl implements SmsService {
public String send(String message) {
System.out.println("Send message: " + message);
return null;
}
}
// Target Ouput
Before method send
Send message: java
After method send
1. 静态代理
// 代理类
public class SmsProxy implements SmsService {
private final SmsService smsService;
public SmsProxy(SmsService smsService) {
this.smsService = smsService;
}
@Override
public String send(String message) {
System.out.println("Before method send()");
smsService.send(message);
System.out.println("After method send()");
return null;
}
}
// Usage
public class Main {
public static void main(String[] args) {
SmsService smsService = new SmsServiceImpl();
SmsProxy smsProxy = new SmsProxy(smsService);
smsProxy.send("java");
}
}
2. JDK 动态代理
在 Java 动态代理机制中,InvocationHandler
接口用于自定义处理逻辑,Proxy
类的 newProxyInstance()
方法用于生成代理对象。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
......
}
实现
// 定义一个动态代理类,实现 InvocationHandler,并重写 invoke 方法
public class MyInvocationHandler implements InvocationHandler {
private final Object target; // 需要被代理的真实对象
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws InvocationTargetException, IllegalAccessException {
System.out.println("Before method " + method.getName());
Object result = method.invoke(target, args);
System.out.println("After method " + method.getName());
return result;
}
}
// 定义一个获取代理对象的工厂类
public class JdkProxyFactory {
public static Object getProxy(Object target) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), // 目标类的类加载器
target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
new MyInvocationHandler(target); // 指定自定义 InvocationHandler
)
}
}
// Usage
SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
smsService.send("java");
3. CGLIB 动态代理
依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
实现
// 定义一个方法拦截器,实现 MethodInterceptor,并重写 intercept 方法
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("Before method " + method.getName());
Object object = methodProxy.invokeSuper(target, args);
System.out.println("After method " + method.getName());
return object;
}
}
// 定义一个获取代理对象的工厂类
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(clazz.getClassLoader());
enhancer.setSuperclass(clazz);
enhancer.setCallback(new MyMethodInterceptor());
return enhancer.create();
}
}
// Usage
AliSmsService aliSmsService = (AliSmsService) CglibProxyFactory.getProxy(AliSmsService.class);
aliSmsService.send("java");
4. 三种方式的对比
- 静态代理中,接口一旦增加新方法,目标对象和代理对象都要进行修改;而动态代理不需要实现接口,可以直接代理实现类,并且不需要对每个目标类都创建一个代理类。
- 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的
class
文件;而动态代理是在运行时动态生成类字节码,并加载到JVM中的。 - JDK动态代理只能代理实现了接口的类或者直接代理接口,而CGLIB可以代理未实现任何接口的类。
- JDK动态代理效率相较于CGLIB更加优秀。
- CGLIB是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为
final
类型的类和方法。
命令模式
文章标题:设计模式
文章作者:nek0peko
文章链接:https://nek0peko.com/index.php/archives/170/
商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,未经站长允许不得对文章文字内容进行修改演绎。
本文采用创作共用保留署名-非商业-禁止演绎4.0国际许可证