在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。
代理模式的定义与特点
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。
代理模式的主要优点有:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
其主要缺点是:
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢;
- 增加了系统的复杂度;
代理模式的结构与实现
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。
代理模式中的角色:
- 抽象主题角色(Subject):声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
- 具体主题角色(RealSubject):也称为委托角色或者被代理角色。定义了代理对象所代表的目标对象。
- 代理主题角色(Proxy):也叫委托类、代理类。代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
代理模式的分类
代理模式有三种实现方式:
静态代理: 代理类在程序运行前就编译好,因此称为静态代理。代理对象和被代理对象都要实现相同的接口或者继承相同的父类(除Object之外),一旦接口或者父类添加、修改方法,子类都要统一更改,违背开闭原则,因此静态代理具有一定的局限性。
动态代理: 利用JDK的API,动态的在内存中构建代理对象。不需要继承父类,可扩展性高。
Cglib代理: 上面两种代理方式目标对象都需要实现接口,但有时候并不是所有目标对象都要实现接口,因此可以使用Cglib框架实现普通类的代理。
静态代理
IHttpInvoke(抽象角色):
public interface IHttpInvoke {
String invoke(String request);
}
Server(目标对象):
public class Server implements IHttpInvoke {
Logger logger = Logger.getLogger(String.valueOf(getClass()));
@Override
public String invoke(String request) {
String response = "没有的,不存在的!";
return response;
}
}
HttpInvokeProxy(代理对象):
public class HttpInvokeProxy implements IHttpInvoke {
private Logger logger = Logger.getLogger(String.valueOf(getClass()));
private IHttpInvoke iHttpInvoke;
public HttpInvokeProxy(IHttpInvoke iHttpInvoke) {
this.iHttpInvoke = iHttpInvoke;
}
@Override
public String invoke(String request) {
String req = before(request);
String response = iHttpInvoke.invoke(req);
after(response);
return response;
}
public String before(String request){
logger.info("请求数据:" + request);
byte[] req = request.getBytes();
String requestData = null;
try {
requestData = new String(req,"GBK");
logger.info("转码成功,返回请求数据");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return requestData;
}
public void after(String response){
logger.info("响应数据: " + response);
}
}
Browser(浏览器客户端):
public class Browser {
public static void main(String[] args) {
String request = "给我一个女朋友!";
IHttpInvoke httpInvokeProxy = new HttpInvokeProxy(new Server());
httpInvokeProxy.invoke(request);
}
}
输出结果:
五月 16, 2019 10:25:02 上午 Structural.ProxyPattern.StaticProxy.HttpInvokeProxy before
信息: 请求数据:给我一个女朋友!
五月 16, 2019 10:25:03 上午 Structural.ProxyPattern.StaticProxy.HttpInvokeProxy before
信息: 转码成功,返回请求数据
五月 16, 2019 10:25:03 上午 Structural.ProxyPattern.StaticProxy.HttpInvokeProxy after
信息: 响应数据: 没有的,不存在的!
静态代理的UML:
动态代理
IHttpInvoke(抽象角色):
public interface IHttpInvoke {
String invoke(String request);
}
Server(目标对象):
public class Server implements IHttpInvoke {
Logger logger = Logger.getLogger(String.valueOf(getClass()));
@Override
public String invoke(String request) {
String response = "没有的,不存在的!";
return response;
}
}
HttpInvokeProxy(代理对象):
public class HttpInvokeProxy implements InvocationHandler {
private Logger logger = Logger.getLogger(String.valueOf(getClass()));
private Object obj;
public HttpInvokeProxy(Object obj) {
this.obj = obj;
}
public String before(String request){
logger.info("请求数据:" + request);
byte[] req = request.getBytes();
String requestData = null;
try {
requestData = new String(req,"GBK");
logger.info("转码成功,返回请求数据");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return requestData;
}
public void after(String response){
logger.info("响应数据: " + response);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before((String) args[0]);
Object object = method.invoke(obj,args);
after((String) object);
return object;
}
}
Browser(浏览器客户端):
public class Browser {
public static void main(String[] args) {
String request = "给我一个女朋友!";
Server server = new Server();
InvocationHandler invocationHandler = new HttpInvokeProxy(server);
Class cls = server.getClass();
IHttpInvoke httpInvoke = (IHttpInvoke) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),invocationHandler);
httpInvoke.httpInvoke(request);
}
}
输出结果:
五月 16, 2019 10:53:01 上午 Structural.ProxyPattern.DynamicProxy.HttpInvokeProxy before
信息: 请求数据:给我一个女朋友!
五月 16, 2019 10:53:02 上午 Structural.ProxyPattern.DynamicProxy.HttpInvokeProxy before
信息: 转码成功,返回请求数据
五月 16, 2019 10:53:02 上午 Structural.ProxyPattern.DynamicProxy.HttpInvokeProxy after
信息: 响应数据: 没有的,不存在的!
Cglib代理
Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
*使用Cglib代理需要引入Cglib的jar包,而且还需要引入asm-all的jar包。注意两个包的版本号,因为不同的版本可能不兼容导致报错。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>asm</groupId>
<artifactId>asm-all</artifactId>
<version>3.3</version>
</dependency>
Server(目标对象):
public class Server{
Logger logger = Logger.getLogger(String.valueOf(getClass()));
public String receiveRequest(String request) {
String response = "没有的,不存在的!";
return response;
}
}
HttpInvokeProxy代理类:
public class HttpInvokeProxy implements MethodInterceptor {
private Logger logger = Logger.getLogger(String.valueOf(getClass()));
private Object obj;
public HttpInvokeProxy() {
}
public HttpInvokeProxy(Object obj) {
this.obj = obj;
}
public String before(String request){
logger.info("请求数据:" + request);
byte[] req = request.getBytes();
String requestData = null;
try {
requestData = new String(req,"GBK");
logger.info("转码成功,返回请求数据");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return requestData;
}
public void after(String response){
logger.info("响应数据: " + response);
}
public Object getProxy(){
//1.工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(Server.class);
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类(代理对象)
Object object = enhancer.create();
return object;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before((String) objects[0]);
Object obj = methodProxy.invokeSuper(o,objects);
after((String) obj);
return obj;
}
}
Browser(浏览器客户端):
public class Browser {
public static void main(String[] args) {
String request = "给我一个女朋友!";
Server server = new Server();
Server proxy = (Server) new HttpInvokeProxy(server).getProxy();
proxy.receiveRequest(request);
}
}
输出结果:
五月 16, 2019 11:52:42 上午 Structural.ProxyPattern.CglibProxy.HttpInvokeProxy before
信息: 请求数据:给我一个女朋友!
五月 16, 2019 11:52:42 上午 Structural.ProxyPattern.CglibProxy.HttpInvokeProxy before
信息: 转码成功,返回请求数据
五月 16, 2019 11:52:42 上午 Structural.ProxyPattern.CglibProxy.HttpInvokeProxy after
信息: 响应数据: 没有的,不存在的!
PHP
<?php
/**
* Created by PhpStorm.
* User: LYL
* Date: 2015/5/16
* Time: 16:33
*/
/**顶层接口
* Interface IGiveGift
*/
interface IGiveGift
{
function giveRose();
function giveChocolate();
}
/**追求者
* Class Follower
*/
class Follower implements IGiveGift
{
private $girlName;
function __construct($name='Girl')
{
$this->girlName=$name;
}
function giveRose()
{
echo "{$this->girlName}:这是我送你的玫瑰,望你能喜欢。<br/>";
}
function giveChocolate()
{
echo "{$this->girlName}:这是我送你的巧克力,望你能收下。<br/>";
}
}
/**代理
* Class Proxy
*/
class Proxy implements IGiveGift
{
private $follower;
function __construct($name='Girl')
{
$this->follower=new Follower($name);
}
function giveRose()
{
$this->follower->giveRose();
}
function giveChocolate()
{
$this->follower->giveChocolate();
}
客户端
$proxy=new Proxy('范冰冰');
$proxy->giveRose();
$proxy->giveChocolate();