博主声明:
转载请在开头附加本文链接及作者信息,并标记为转载。本文由博主 威威喵 原创,请多支持与指教。
本文首发于此 博主:威威喵 | 博客主页:https://blog.csdn.net/smile_running
代理模式(Proxy Pattern),是非常贴近我们生活的一个例子,我们实际生活中比比皆是,很多服务行业基本都是和代理相挂钩的。举个例子,比如银行的业务人员,这个我们最熟悉不过了,要去银行办理一些业务的时候,通常都会叫你去找业务代理人员,或者称为业务办理人员,他们所用的就是代理模式,把银行的业务交给业务员去代理。类似这种的销售模式,不仅限于银行,像很多销售楼房、车辆等都一样。
再有就是和计算机息息相关的代理也有很多,比如代理 ip、代理服务器,还有一些代理软件等等。不过代理模式还可以分为两种,一种是:静态代理,另一种是:动态代理。
关于这些事例就介绍到此,我们来看看今天要用的代理模式的定义:一个类代表另一个类的功能,这种类型的设计模式属于结构型模式。在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。为其他对象提供一种代理以控制对这个对象的访问。
了解了一些关于代理模式的知识,我们就可以很快的步入今天的案例。这里呢,以我要去买房的这个例子,来运用代理模式写一下相关代码。
话说这一天,我来到了一家售楼公司里面了解楼盘情况,等到你一进门呢,很多售楼小姐姐就会围上来,口若悬河的向你逐个的介绍楼盘情况。这时候呢,小姐姐通常都是非常热情的,因为只要你买了套房,她们的提成也是挺高的。不过这不是我们关心的,我们应该关心的是这个售楼小姐姐,她在这个例子当中担任什么样的角色。
思考一番,原来她是代理人,她所拥有的技能就是销售各种各样的楼房。好吧,扯完了,代码可以写起来了,来看我们的代理接口,也就是代理人所拥有的技能。
package com.xww.dp.proxy;
/**
* 代理业务接口,有出售小区房、别墅的业务功能,得到的收益不一样。
*
* @author xww
*
*/
public interface SalesProxy {
int sellHouse();// 出售小区房
int sellVilla();// 出售别墅
}
接下来就是这个接口的实现类,也就是向我们销售的小姐姐,这个类需要实现刚刚创建的接口,代表着她拥有了这个能力。
package com.xww.dp.proxy;
/**
* 推销员,销售楼房的人。做为你的代理人。
*
* @author xww
*
*/
public class Salesmen implements SalesProxy {
public Salesmen() {
}
@Override
public int sellHouse() {
System.out.println("销售员:向你推荐了 1 套小区房,1800000元");
return 1800000;
}
@Override
public int sellVilla() {
System.out.println("销售员:向你推荐了 1 套别墅,价格:9000000元");
return 9000000;
}
}
以上数据都为瞎编了,那么既然销售人员是代理人,那么我们自己就是被代理的对象,我们的能力是买房子、考虑要买什么样的房子,就这两个简单的方法,代码如下:
package com.xww.dp.proxy;
/**
* 我们自己,被代理的对象,通过代理人购买房子
*
* @author xww
*
*/
public class Me {
private Salesmen salesmen;
public Me(Salesmen salesmen) {
super();
this.salesmen = salesmen;
}
public void think() {
int money = salesmen.sellVilla();
System.out.println("我:又不是土豪,买不起,买不起!");
}
public void buy() {
int money = salesmen.sellHouse();
System.out.println("我:就这个了,付了" + money + "元");
}
}
因为我们要通过代理人,才能知道一些楼房的相关信息及价格。所以呢,在上面的 Me 类要传入代理人(小姐姐0)的引用,这样我们才能获取到想要的信息。好了,这就是我们的静态代理模式的相关代码,接下来运行看看吧。
客户端代码:
package com.xww.dp.proxy;
/**
* 静态代理模式
*
* @author xww
* @博客:https://blog.csdn.net/smile_running
*/
public class StaticProxyClient {
public static void main(String[] args) {
Salesmen salesmen = new Salesmen();
Me me = new Me(salesmen);
me.think();
me.buy();
}
}
第一次呢,小姐姐向我们推荐了一套别墅,额、你看我像买得起别墅的样子嘛!!然后呢,又给我推荐了一间小区房,我呢就果断的买下来了。
好了,买完房子结束了,开开心心的回了家。静态代理模式就是这样的,看上去代码比较简单,也容易理解。首先我们作为代理人,是没有房源信息的,也就是这个售楼人员,让我们间接的有了房源的信息,就体现了一个类拥有了另一个类的功能,这就是代理模式的概念。
动态代理也是如此,让一个类代表另一个类,让它间接的拥有另一个类的功能。下面我们来看看动态代理是怎么样实现的。
动态代理,是 Jdk 为我们提供的一个方式,对应的类名就叫做 Proxy 类,在 java.lang.reflect 包下面。动态代理理解起来可能有一点困难,看它这个包,就知道动态代理运用的是反射来实现的。
下面呢,我们就使用动态代理模式修改一下代码,看看会有哪一些变化。首先这个 Proxy 类的用法我就不再进行介绍了吧,这个是 Java 基础,与静态代理不同的是,动态代理必须是一个接口类,不是接口还行,因为 Proxy 类要求我们传入的是一个 interface 类型的,这里要对上面的 Me 类进行修改,必须实现接口才行,代码如下:
package com.xww.dp.proxy;
/**
* 我们自己,被代理的对象,通过代理人购买房子
*
* @author xww
*
*/
public class Me implements SalesProxy {
public Salesmen salesmen;
public Me(Salesmen salesmen) {
super();
this.salesmen = salesmen;
}
@Override
public int sellHouse() {
int money = salesmen.sellVilla();
System.out.println("我:又不是土豪,买不起,买不起!");
return 0;
}
@Override
public int sellVilla() {
int money = salesmen.sellHouse();
System.out.println("我:就这个了,付了" + money + "元");
return 0;
}
}
我们把 think() 和 buy() 方法干掉了,留下接口里面的方法即可。因为动态代理反射回来的是一个接口类型,所以我们调用的只能是接口里面的抽象方法,来看我们的具体方法:
package com.xww.dp.proxy;
import java.lang.reflect.Proxy;
/**
* 动态代理。注意: 1、被代理对象必须实现代理的接口
*
* @author xww
*
*/
public class DynamicProxyClient {
public static void main(String[] args) {
Salesmen salesmen = new Salesmen();
Me me = new Me(salesmen);
SalesProxy mProxy = (SalesProxy) Proxy.newProxyInstance(
SalesProxy.class.getClassLoader(),
new Class>[] { SalesProxy.class }, new SalesHandler(me));
mProxy.sellHouse();
mProxy.sellVilla();
}
}
我们实例化了一个 me 对象,并且把它传到了 SalesHandler 里面,因为我们要调用 Salesmen 类的方法,必须要传进去。来看看代码:
package com.xww.dp.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理 - 处理类
*
* @author xww
*
*/
public class SalesHandler implements InvocationHandler {
private Me me;
public SalesHandler(Me me) {
this.me = me;
}
@Override
public Object invoke(Object proxy, Method method, Object[] params)
throws Throwable {
Object obj = method.invoke(me, params);
return obj;
}
}
这里通过 method 调用对象里面的方法,返回的就是一个接口类型,最后 ruturn 回去就是我们的 SalesProxy 接口的对象,拿到该实例已经,就可以调用接口里面的方法了。那么,它的输出也一样如下:
那么至此,动态代理也就写完了。通过对比代码,静态代理和动态代理所使用的方式有所不同,前者是正常的 new 对象,然后调用方法,后者则是通过反射的方式实例化对象,然后才可以调用方法。而且一般来说,动态代理所写的代码,或者是需求增加时要改变的代码量而言,会比静态代理少。
好了,代理模式的两种实现方式就是这样了,那么要怎么选择就需要你根据实际的需求来决定了。