先来看下代理模式的定义和目的
定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
目的:1、通过引入代理对象的方式来简介访问目标对象,防止直接访问目标对象给系统带来不必要的复杂性
2、通过代理对象对原有的业务增强
好吧,这看上去完全不像人话,那我举个例子把这个说成人话把。如下:
张三现在想点东西,给生活带来一点激情,这类好东西呢一般都在国外那边的某些公司才有生成。如果张三直接跑过去买,不仅要购买飞机票,跑来跑去,而且去了也不会说外国话,万一别人理解错了就麻烦大了。而且啊,买到了你要自己带着这么刺激的东西会不会很紧张,被发现了多尴尬。这搞下来不得麻烦死,所以干脆找代理。啥都不用管,只需要把需求给代理讲清楚,代理做专业的市场调研给你找最好的货,买到了给你提供精美的包装海外快递过来一条龙服务并且之后有问题随时咨询,算不算增强了你原本的需求。代理模式给我们带来了很多便捷。
上图基本逻辑如上图。在程序中也是如此,通过代理,可以详细控制访问某个或者某类对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。这也是AOP的实现原理。
那么代理模式的核心角色该如何设计呢?
1、静态代理
根据上面的实现步骤,首先来写一个抽象角色:
/***
* 抽象类:某激情公司接口
*/
public interface PassionCompany {
public void saleManPassion(String type); //产品尺寸
}
这个抽象类中有一个方法,现在分别让真实角色和代理角色来实现该抽象类:
/***
* 真实对象,提供张三需要的产品的公司
*/
public class ManPassionCompany implements PassionCompany {
@Override
public void saleManPassion(String type){
System.out.println("售卖产品尺寸"+type);
}
}
真实对象继承抽象类,重写方法
/***
* 代理类,集成接口并将真是类包含进来,然后对真实对象增强,提供更好的售前售后服务
*/
public class PassionProxy implements PassionCompany {
private ManPassionCompany manPassionCompany;
public PassionProxy(ManPassionCompany manPassionCompany) { //将真实对象包含进来
this.manPassionCompany = manPassionCompany;
}
@Override
public void saleManPassion(String type){
preSales();
manPassionCompany.saleManPassion(type);
afterSales();
}
public void preSales(){
System.out.println("代理提供一品的售前服务");
}
public void afterSales(){
System.out.println("代理提供售后的一条龙服务");
}
}
真实对象和代理对象都写好了,代理对象中我们对真实对象进行了额外的相关服务,有点类似装饰者模式。
/***
* 测试类
*/
public class ProxyClient {
public static void main(String[] args) {
ManPassionCompany passionCompany= new ManPassionCompany();
PassionProxy passionProxy= new PassionProxy(passionCompany);
passionProxy.saleManPassion("3");
}
}
输出结果:
- 代理提供一品的售前服务
- 售卖产品尺寸3
- 代理提供售后的一条龙服务
可以看出,张三只跟代理对象打交道,代理对象把能做的都做了,比如购买激情产品之前的调研和售后打包一条龙服务,只是把去真实对象采购就阔以了。
2. 动态代理
静态代理讲完了,那么接下来就是动态代理。首先需要思考一个问题,有了静态代理了之后为什么需要动态代理。
来来来,我们在静态代理的基础上思考一下,现在只是张三要买东西,万一以后张三的老婆要买女性,李四买动漫、王五买化妆品也找那个代理,或者张三哪天又想买非type类型的产品要来个sex类型的,那么真实的类中的里面是不是业务更加复杂了,还要去修改里面的代码,继承更多的接口,可维护性差扩展性也不好,不符合代理模式的基本准备——开闭准则。那么应该怎么完美的解决这个问题呢,既然有专门做激情代理的,代理的圈子内各有不同的专业,整合到一起成立一个代理集合,这样每次根据客户需求安排相应的代理去完成。注意一下,这里怎么安排的呢。其实就是核心机制就是反射机制。
代理模式图变成如下:(本质没有变化)
这里lison代理公司的核心机制是什么:
- Proxy:根据代购需求调用公司具备改代购需求专业的员工去做。——>通过newProxyInstance生成动态代理对象
- InvocationHandler:是个接口,只有一个invoke()方法,就是对业务增强的方法。
遵循代理基本原则单一职责原则,某个类只负责一个业务能力。职责划分非常清晰。
再来根据上图逻辑我们来写代码。
首先我们需要注册一个代理公司,不同的需求可以分配不同专业方向的员工去做。
public class PassionProxyCompany implements InvocationHandler {
//被代理的对象
private Object company;
public Object getCompany() {
return company;
}
public void setCompany(Object company) {
this.company = company;
}
//通过Proxy获取动态代理的对象
public Object getProxyInstance(){
return Proxy.newProxyInstance(company.getClass().getClassLoader(),company.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method,Object[] args) throws InvocationTargetException, IllegalAccessException {
// 在代理真实对象前,增强业务
doSomeThingBefore();
//这里要进行动态代理不知道调用那个对象,所以将method对象的方法作为参数传入,根据反射调用要优化的方法。
Object ret = method.invoke(company, args);
// 在代理真实对象之后,增强业务
doSomeThingAfter();
return ret;
}
public void doSomeThingBefore(){
System.out.println("根据需求,进行市场调研和产品分析");
}
public void doSomeThingAfter(){
System.out.println("精美包装,一条龙服务");
}
PassionCompany里面包含核心业务,一个是根据需求分配员工Proxy,第二个是增强的业务invoke();
然后我们测试一下: 注意这里生成的真实类是父类引用指向子类对象
public class dtProxy {
public static void main(String[] args) {
//生成男性用品
APassionCompany man = new ManPassionCompany();
//生成女性用品
BPassionCompany woman = new WomanPassionCompany();
//代理公司
PassionProxyCompany passionProxyCompany = new PassionProxyCompany();
//张三来找我,购买男用品
passionProxyCompany.setCompany(man);
//分配给专门的1号员工去做
APassionCompany lison1 = (APassionCompany)passionProxyCompany.getProxyInstance();
lison1.saleManPassion("D");
System.out.println("-------------------------");
//张三老婆来找我,购买女性用品
passionProxyCompany.setCompany(woman);
//分配给专门的2号员工去做
BPassionCompany lison2 = (BPassionCompany)passionProxyCompany.getProxyInstance();
lison2.saleWomanPassion(18);
}
}
输出结果为:
- 根据需求,进行市场调研和产品分析
- 售卖产品尺寸D
- 精美包装,一条龙服务
- -------------------------
- 根据需求,进行市场调研和产品分析
- 售卖产品尺寸18
- 精美包装,一条龙服务
由此可见,使用代理可以在执行某个逻辑的前后加上新的逻辑,这是很好的功能,实际中Spring的AOP用的就是这种技术。
下篇会接着说,proxy里面到底做了什么。