动态代理模式解决装饰者设计模式的缺陷

先来看看代理的引入:

代理就是在程序的执行过程中,通过一个类Proxy和接口invacationHandler(处理程序)实现动态代理

先创建一个接口里面有我们需要的方法(就是我们需要代理的对象):


package com.qf.InvocationHandler;
/**
 * 来实现一个增删改查的代理
 *
 */
public interface UserDao {
 
public abstract void add();//增加
public abstract void delete();//删除
public abstract void modify();//修改
public abstract void find();//查询
 
}

再去创建一个它的子实现类去实现它的方法:


package com.qf.InvocationHandler;
 
public class UserDaoImpl implements UserDao{
 
@Override
public void add() {
System.out.println("调用了增加功能");
}
 
@Override
public void delete() {
System.out.println("调用了删除功能");
}
 
@Override
public void modify() {
System.out.println("调用了修改功能");
}
 
@Override
public void find() {
System.out.println("调用了查询功能");
}
}

创建一个子实现类去实现InvocationHandler代理接口:

package com.qf.InvocationHandler;
/**
 * 创建一个子实现类去实现InvocationHandler代理接口
 */
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class MyInvocationHandler implements InvocationHandler {
 
//我们首先定义一个需要代理的对象
private Object target;
 
//创建该类的有参构造
public MyInvocationHandler (Object target) {
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//实现代理的程序
//invoke方法就是实现代理的方法
System.out.println("权限校验");
Object obj = method.invoke(target, args);
System.out.println("日志记录");
return obj;
}
 
}

最后创建一个测试类:

package com.qf.InvocationHandler;
 
import java.lang.reflect.Proxy;
 
public class UserTest {
 
public static void main(String[] args) {
 
//创建UserDao对象,使用多态的形式
UserDao ud=new UserDaoImpl();
ud.add();
ud.delete();
ud.modify();
ud.find();
 
System.out.println("-----------------------------");
 
//创建MyInvocationHandler类对象
MyInvocationHandler handler=new MyInvocationHandler(ud);
 
/**
 * 我们需要代理的对象时UserDao接口
 * 所以下面的newProxyInstance方法中的对象就是UserDao接口的对象
 * loader:就是代理对象先获取字节码文件再去获取它的类加载器类(loader)
 * interfaces:就是代理对象所表示的类或接口所实现的接口
 * 同样是先获取字节码文件再去调用getInterfaces()方法
 * h:就是InvocationHandler接口本身或者他的子实现类对象
 */
 
//以为这里的代理对象时UserDao所以我们需要将类型强制转化成UserDao类型
UserDao ud2 = (UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(), handler);
ud2.add();
ud2.delete();
ud2.modify();
ud2.find();
}
}
 
运行结果:
调用了增加功能
调用了删除功能
调用了修改功能
调用了查询功能
-----------------------------
权限校验
调用了增加功能
日志记录
权限校验
调用了删除功能
日志记录
权限校验
调用了修改功能
日志记录
权限校验
调用了查询功能
日志记录

总结成一句话就是:不改变需要装饰(增强)的类的原代码.使用jdk原生的proxy类的方法newProxyInstance来创建一个实现类,完成对原方法的逻辑增强, 多态的形式将实现类返回给一个接口对象。

装饰者模式: 静态代理

1.壳子(装饰者类)必须跟 原本对象 实现同一个接口,保证调用方法 跟以前没有区别 上层不用改
2.装饰者类 必须持有原本对象的引用 (提供构造方法,传入原本实现类),装饰者不是真正逻辑,只是为了给原方法额外增加一些通用型逻辑(例如添加sql事务)
3.不需要增强的就完全直接调用原本实现类
4.需要增强得随便加逻辑

优点:可以无侵入(不修改源代码)增强逻辑

缺点: 需要给每一个需要增强的类手动套壳,
  需要实现接口中的所有抽象方法
  导致类结构爆炸
  
一句话概述:不改变需要装饰(增强)的类的代码.新写一个包装类,给需要装饰的类的方法添加上新的业务代码,不需要装饰的方法则返回原方法.


不难发现,动态代理和装饰者模式很相似,两者的区别就是代理模式主要是控制对某个特定对象访问,而装饰模式主要是为了给对象添加行为

发布了21 篇原创文章 · 获赞 4 · 访问量 185

猜你喜欢

转载自blog.csdn.net/weixin_46221109/article/details/104848108
今日推荐