代理模式
静态代理
这里就举个例子,比如你某天要去上班,但是车突然坏了,然后你又急着去上班,所以将叫人将车拖到到店里交给修理工去修车,然后你自己就正常的去上班了。
- 首先定义一个接口,接口里就可以定义你需要代理的方法
public interface Repair {
void repair();
}
- 定义被代理类。
public class You implements Repair{
@Override
public void repair() {
System.out.println("修理汽车");
}
}
- 定义代理类,注意!代理类和被代理类都需要去实现Repair接口。
// 静态代理的好处:
// 1.将修理方法交给代理类处理,You类就可以做其他的事情。比如你将修车的任务交给修理工,你自己呢就可以正常上班了。
// 2.代理类可以做很多You类做不到的事情,比如before(),after(),就例如这里的例子,如果只是你自己来修车,有可能就拿个扳手在那里敲敲打打,弄对了可能车就修好了,没弄对可能还是那样。但是如果交给代理类的话,他就直接给你来个一条龙服务了。
public class Repairman implements Repair{
private Repair repair;
public Repairman(Repair repair) {
this.repair = repair;
}
@Override
public void repair() {
before();
repair.repair();
after();
}
private void before(){
System.out.println("修理工检查问题");
}
private void after(){
System.out.println("修理工给你修好车之后呢,再顺便给你的车做一次保养");
}
}
- 最后写个测试类试一下。
public class Test01{
public static void main(String[] args) {
// 静态代理
// 这里使用了一个例子,你汽车坏了,但是你修理起来很麻烦,只想让修理工来修,这就是代理
// 在代码里的体现就是,两个类都实现了修理的这个接口,然后将需要被代理的对象通过参数传递给代理类,然后由代理类来调用修理方法
Repairman repairman = new Repairman(new You());
repairman.repair();
// 简化一下就是这样
//new Repairman(new You()).repair();
}
}
总结一下,代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介,或者说这里的修理工,让他们去做一些自己做不到或者不想做的事情。
代理模式和装饰者模式的区别
可能有些人觉得这代理模式不就是对类的一个拓展吗,那和装饰者模式有啥区别?其实区别还是有的。
- 代理模式是让别人帮自己做一些自己做不到或者不想做的事,这种事情的重要性可能不是特别高,比如你车坏了,如果花时间自己去修车上班就迟到了,而且车坏了也可以坐公交车呀,但是上班迟到了就直接扣工资了。
- 装饰者模式是让自己的能力增强,使得增强后的自己能够使用更多的方法,拓展在自己基础之上的功能的。就还是这个例子,本来自己不会修车,但是想自己学习一下这个技术,以后车坏了就可以自己修车了,这就是对自己的增强。
总结一下,对于修车这件事,在自己不擅长修车的情况下,代理模式的解决办法是找修理工帮忙修车,装饰者模式的解决办法是自己学习修车的这个技术,然后自己修。同一个问题,他们最终的目的是一样的,只是解决办法不同而已。所以在实际使用的时候,要考虑到应用场景和成本来使用对应的模式。
动态代理
- 还是一样的代码,先定义一个接口
public interface UserService {
void add();
void delete();
void update();
void select();
}
- 再定义被代理类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("新增了一个用户");
}
@Override
public void delete() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("修改了一个用户");
}
@Override
public void select() {
System.out.println("选择了一个用户");
}
}
- 这里就看看动态代理具体是怎么实现的
// 动态代理
// 代理模式如静态代理的好处在不改动原本的代码的情况下,增加一些格外的功能,如这里的日志功能
// 而动态代理就是在静态代理的基础上升级,可以不用一个接口的每个实现类都去加一个代理类
// 当然这里的例子其实就是一个封装好的工具类了,可以直接拿来用了
public class ProxyDemo implements InvocationHandler {
private Object target;
// 将需要代理的对象传递就进来,之前是用构造来设置的,这里还是建议用set方法
public void setTarget(Object target) {
this.target = target;
}
// 生成代理类
public Object getProxy() {
// 这里就是通过反射获取它的类加载器,接口,第三个参数类型是InvocationHandler,因为ProxyDemo实现了InvocationHandler接口
// 所以直接用this就行
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
// 执行
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());// 这就是动态代理,插入日志
Object result = method.invoke(target, args);
return result;
}
private void log(String msg) {
System.out.println("执行了" + msg + "方法");
}
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
ProxyDemo proxyDemo = new ProxyDemo();
proxyDemo.setTarget(userService);
// 只要你是实现了UserService这个接口,无论多少个实现类,它都可以通过一个代理类搞定
// 而静态代理就不一样了,你想要有多个实现类使用代理模式,那么你就要去写多少个代理类
UserService service = (UserService) proxyDemo.getProxy();
// 这里调用add方法其实就是调用了动态代理里的invoke()方法,在这个方法里又通过反射调用真正的add方法
service.add();
// 下面的是一样的了,不做解释
service.update();
service.select();
service.delete();
}
}
到了现在,应该已经明白代理模式是干嘛的了吧,那么spring中的AOP(面向切面)就是基于动态代理实现的,看上面的代码,我们可以在不改动原本代码的情况下,在每个方法执行后都记录一次日志,这就是面向切面。