前言
从业几年,工作上一直忙于各种业务,自己的时间少了,学习动力一点点耗尽,再加上本身又比较懒散,慢慢就放下钻研了,偶尔心血来潮会翻翻技术相关的书,却发现里面的东西总是一知半解。相信很多人也和我一样困于这个状态,一直如此总不是个办法,想想还是决定写写博客,复习巩固下知识。
正巧最近想深入了解下持久化框架,大致翻了下书,代理的出现频率挺高,就作为首个需要复习的点吧。
1、阐述代理
1.1、什么是代理?
引用《Java编程思想》中对代理的解释:代理是基本的设计模式之一,它是你为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色。
如果感觉还是很抽象很模糊,那结合我们的生活就好了。以老师为例,老师要批改作业,但是这之前肯定要收作业,又不想自己去收,怎么办呢?不如选个课代表吧,收作业的事叫课代表干了,老师仅专注于批改作业。如此,课代表就是老师的代理,课代表作为“代理对象”代替了老师这个“实际对象”去收取学生的作业,充当老师和学生的中间人角色,实现最终批改作业的目的。
从上面的例子我们就能发现,代理有些非常明显的好处:
功能增强:能更方便的对实际对象的功能进行扩展(除了可以让课代表收作业,还可以让其做更多其他事)。
控制访问:有效把控对实际对象的操作和访问(老师如果和一个个去学生那收作业批改作业,就要承受更多的任务和压力,有个课代表作为中间人就不那么累了)。
解耦合:降低代码的耦合度,减少相互依赖(老师只需要专注于批改作业,杂七杂八的事可以直接交给课代表)。
到此,大家对代理有个大致的理解了,概念并不复杂。
1.2、代理的分类
根据代理创建的时期区分,我们可将代理分成两大类:静态代理与动态代理。
什么是静态代理?什么又是动态代理?
静态代理就是在代码编译时,就已经确定了代理对象和被代理对象的关系,即我们编写代码的时就已经实际创建了代理对象。
反之,如果代理对象不是直接在编写代码时创建,而是在我们程序运行期间生成,即是动态代理。在java中,动态代理也分很多种模式,后续主要会拿大家说的比较多的JDK动态代理和CGLIB动态代理作为主要示例。
2、静态代理的实现
接下来就用实际代码来演示静态代理的实现。
1、首先,创建一个Person接口,包含一个doSomething方法。老师和课代表都是人,都会做事,所以后续的老师类(实际对象)和课代表(代理对象)类都会实现这个接口:
public interface Person {
void doSomething();
}
2、创建老师类(实际对象),实际做的事是批改作业:
/**
* 老师
*/
public class Teacher implements Person {
@Override
public void doSomething() {
System.out.println("老师:批改作业");
}
}
3、创建课代表类(代理对象),实际做的事是收作业,交由老师批改,批改完成后发回作业。
/**
* 课代表
*/
public class Representative implements Person {
private Person teacher;
public Representative(Person teacher) {
this.teacher = teacher;
}
@Override
public void doSomething() {
System.out.println("课代表:收作业");
teacher.doSomething();
System.out.println("课代表:发作业");
}
}
4、再来创建一个学生类(请求发起对象)来交作业:
/**
* 学生
*/
public class Student {
//交作业
public void handInHomework(Person person) {
System.out.println("学生:交作业");
person.doSomething();
}
}
5、先来看看没有代理的情况和结果,学生直接将作业交给老师:
public class StaticTest {
public static void main(String[] args) {
//老师
Person teacher = new Teacher();
//学生
Student student = new Student();
//交作业
student.handInHomework(teacher);
}
}
学生:交作业
老师:批改作业
6、有代理的情况,学生将作业交给课代表:
public class StaticTest {
public static void main(String[] args) {
//老师
Person teacher = new Teacher();
//课代表
Person representative = new Representative(teacher);
//学生
Student student = new Student();
//交作业
student.handInHomework(representative);
}
}
学生:交作业
课代表:收作业
老师:批改作业
课代表:发作业
从以上代码可以看到,学生提交作业时,并不需要关心作业具体提交给老师还是课代表,因为老师和课代表共同实现了Person接口,课代表作为学生和老师的中间人,将除了批改作业外的其他事情接管。
总结
虽然了解类静态代理的实现和作用,但静态代理的弊端也是比较明显的,由于代理对象都是编译时就直接手动创建的,虽然一定程度上也做到了解耦合,但这还远远不够。当对象新增方法,或有需要代理的新类型的实际对象时,就需要对代理对象进行修改甚至编写新的代理,这种做法很不灵活,实用场景也稍少。
作为一名懒惰的程序员,不想去一个个编写,那怎么办呢?动态代理是很好的替代方案,后续章节我们就继续延伸讲讲动态代理,待续......