代理模式
定义
代理模式(Proxy Pattern)也叫委托模式,是构造型的设计模式之一,就是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。
英文定义:Provide a surrogate or placeholder for another object to control access to it .
代理模式的UML图示如下所示:

上图中主要涉及如下角色:
- 抽象主题(Subject):真是主题与代理主题的共同接口。
- 真实主题(RealSubject):定义了代理角色所代表的真实对象。
- 代理主题(Proxy):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主体对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
代理模式的通用代码如下所示:
//抽象主题类
public interface Subject{
//定义一个方法
public void request();
}
//真实主题类
public class RealSubject implements Subject{
//实现方法
public void request(){
//业务逻辑处理
}
}
public class Proxy implements Subject{
//要代理哪个实现类
private Subject subject = null;
//默认被代理者
public Proxy(){
this.subject = new Proxy();
}
//通过构造函数传递代理者
public Proxy(Object...objects){
}
//实现接口中定义的方法
public void request(){
this.before();
this.subject.request();
this.after();
}
//预处理
private void before(){
//do something
}
//善后处理
private void after(){
//do something
}
}
优缺点
优点:
- 职责清晰:真实的角色就是实现实际的业务逻辑,不关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰。
- 高扩展性
- 智能化
什么时候要使用代理模式?
在对已有的方法进行使用时出现需要对原有方法进行改进或者修改时,有两种改进选择:
- 修改原有方法来适应现在的使用方式;
- 使用一个“第三者”方法来调用原有的方法并且对方法产生的结果进行一定的控制。
下面是常见的几种代理模式:
- 远程代理:为一个位于不同的地址空间的对象提供一个局域代表对象。
- 虚拟代理:根据需要将一个资源消耗很大或者比较复杂的对象延迟,在真正需要时才创建。
- Copy-on-Write代理:虚拟代理的一种。把复制拖延到只有在客户端需要时才真正地采取行动。
- 保护代理:控制对一个对象的访问权限。
- Cache代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这个结果。
- 防火墙代理:保护目标,不让恶意用户接近。
- 同步化代理:使几个用户能够同时使用一个对象而没有冲突。
- 智能引用代理:提供比对目标对象额外的服务。
代理模式一般应用于以下情况:
- 一个比较大的对象,需要很长的载入时间。
- 一个需要很长时间才可以完成的计算结果,并且需要它在计算过程中显示中间结果。
- 一个存在于远程计算机上的对象,需要通过网络载入这个远程对象就需要很长的时间,特别是在网络传输的高峰期。
扩展
1.普通代理
在网络上代理服务器设置分为透明代理和普通代理。
透明代理:就是用户不用设置代理服务器地址,就可以直接访问,也就是说代理服务器对用户来说是透明的,不用知道它存在的。
普通代理:需要用户自己设置代理服务器的IP地址,用户必须知道代理的存在。
在设计模式中的普通代理和强制代理也是类似的一种结构。
普通代理:我们要知道代理的存在,然后才能访问。
强制代理:调用者直接调用真是角色,而不用关心代理是否存在,其代理的产生是由真是角色决定。
普通代理的UML类图如下所示:

代码示例如下:
//玩家接口
public interface IGamePlayer{
//登录游戏
public void login(String name,String password);
//杀怪
public void killBoss();
//升级
public void upGrade();
}
//普通代理的玩家
public class GamePlayer implements IGamePlayer{
private String name = "";
//构造函数限制谁能创建对象,并同时传递姓名
public GamePlayer(IGamePlayer iGamePlayer,String name) throws Exception{
if(iGamePlayer==null){
throw new Exception("不能创建真实角色!");
}else{
this.name = name;
}
}
//打怪
public void kiilBoss(){
System.out.println(this.name+"在打怪!");
}
//登录游戏
public void login(String user , String password){
System.out.println("用户名为"user+"的用户"this.name+"登陆成功!");
}
//升级
public void upGrade(){
System.out.println(this.name+"又升了一级!");
}
}
//普通代理的代理者
public class GamePlayerProxy implements IGamePlayer{
private IGamePlayer iGamePlayer = null;
//通过构造函数传递要对谁进行代练
public GamePlayerProxy(String name){
try{
gamePlayer = new GamePlayer(this,name);
}cathch(Exception e){
//异常处理
}
}
//代练杀怪
public void killBoss(){
this.gamePlayer.killBoss();
}
//代练登录
public void login(String name , String password){
this.gamePlayer.login(user,password);
}
//代练升级
public void upGrade(){
this.gamePlayer.upGrade();
}
}
//普通代理的场景类
public class Client{
public static void main(String[] args){
//定义一个代练
IGamePlayer proxy = new GamePlayerProxy("张三");
//开始打游戏
System.out.println("开始时间是:2017-4-20 10:45");
proxy.login("zhangSan","password");
//开始杀怪
proxy.killBoss();
//升级
proxy.upGrade();
//记录结束游戏时间
System.out.println("结束时间是:2017-4-21 058:34");
}
}
强制代理的UML类图如下所示:

强制代理的示例代码如下:
//强制代理的接口类
public interface IGamePlayer{
//登录游戏
public void login(String name,String password);
//杀怪
public void killBoss();
//升级
public void upGrade();
//每个人都可以找一下自己的代理
public IGamePlayer getProxy();
}
//强制代理的真实角色
public class GamePlayer implements IGamePlayer{
private String name = "";
private IGamePlayer proxy = null;
public GamePlayer(String name){
this.name = name;
}
//找到自己的代理
public IGamePlayer getProxy(){
this.proxy = new GamePlayerProxy(this);
return this.proxy;
}
//打怪
public void kiilBoss(){
if(this.isProxy()){
System.out.println(this.name+"在打怪!");
}else{
System.out.println("请使用指定的代理访问!");
}
}
//登录游戏
public void login(String user , String password){
if(this.isProxy()){
System.out.println("用户名为"user+"的用户"this.name+"登陆成功!");
}else{
System.out.println("请使用指定的代理访问!");
}
}
//升级
public void upGrade(){
if(this.isProxy()){
System.out.println(this.name+"又升了一级!");
}else{
System.out.println("请使用指定的代理访问!");
}
}
//校验是否是代理访问
private boolean isProxy(){
if(this.proxy == null){
return false;
}else{
return true;
}
}
}
//强制代理的代理类
public class GamePlayerProxy implements IGamePlayer{
private IGamePlayer iGamePlayer = null;
//通过构造函数传递要对谁进行代练
public GamePlayerProxy(IGamePlayer iGamePlayer){
this.iGamePlayer = iGamePlayer;
}
//代练杀怪
public void killBoss(){
this.gamePlayer.killBoss();
}
//代练登录
public void login(String name , String password){
this.gamePlayer.login(user,password);
}
//代练升级
public void upGrade(){
this.gamePlayer.upGrade();
}
//代理的代理暂时没有
public IGamePlayer getProxy(){
return this;
}
}
//直接访问真实角色
public class Client{
public static void main(String[] args){
//定义一个游戏的角色
IGamePlayer player = new GamePlayer("张三");
//开始打游戏
System.out.println("开始时间是:2017-4-20 10:45");
player.login("zhangSan","password");
//开始杀怪
player.killBoss();
//升级
player.upGrade();
//记录结束游戏时间
System.out.println("结束时间是:2017-4-21 058:34");
}
}
//直接访问代理类
public class Client{
public static void main(String[] args){
//定义一个游戏的角色
IGamePlayer player = new GamePlayer("张三");
//定义一个代练
IGamePlayer proxy = new GamePlayerProxy(player);
//开始打游戏
System.out.println("开始时间是:2017-4-20 10:45");
proxy.login("zhangSan","password");
//开始杀怪
proxy.killBoss();
//升级
proxy.upGrade();
//记录结束游戏时间
System.out.println("结束时间是:2017-4-21 058:34");
}
}
//强制代理的场景类
public class Client{
public static void main(String[] args){
//定义一个游戏的角色
IGamePlayer player = new GamePlayer("张三");
//获取指定的代理
IGamePlayer proxy = player.getProxy();
//开始打游戏
System.out.println("开始时间是:2017-4-20 10:45");
proxy.login("zhangSan","password");
//开始杀怪
proxy.killBoss();
//升级
proxy.upGrade();
//记录结束游戏时间
System.out.println("结束时间是:2017-4-21 058:34");
}
}
2.有个性的代理
一个类可以实现多个接口,完成不同人物的整合。代理类不仅仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上做增强(对目标对象的方法进行拦截和过滤)。
UNL类图如下所示:

示例代码如下:
//代理类的接口
public interface IProxy{
//计算费用
public void count();
}
//代理类
public class GamePlayerProxy implements IGamePlayer,IProxy{
private IGamePlayer iGamePlayer = null;
//通过构造函数传递要对谁进行代练
public GamePlayerProxy(IGamePlayer iGamePlayer){
this.iGamePlayer = iGamePlayer;
}
//代练杀怪
public void killBoss(){
this.gamePlayer.killBoss();
}
//代练登录
public void login(String name , String password){
this.gamePlayer.login(user,password);
}
//代练升级
public void upGrade(){
this.gamePlayer.upGrade();
}
//代理的代理暂时没有
public void count(){
System.out.println("");
}
}
//玩家接口
public interface IGamePlayer{
//登录游戏
public void login(String name,String password);
//杀怪
public void killBoss();
//升级
public void upGrade();
}
//玩家
public class GamePlayer implements IGamePlayer{
private String name = "";
//通过构造函数传递名称
public GamePlayer(String name){
this.name = name;
}
//打怪
public void kiilBoss(){
System.out.println(this.name+"在打怪!");
}
//登录游戏
public void login(String user , String password){
System.out.println("用户名为"user+"的用户"this.name+"登陆成功!");
}
//升级
public void upGrade(){
System.out.println(this.name+"又升了一级!");
}
}
//场景类
public class Client{
public static void main(String[] args){
//定义一个玩家
IGamePlayer player = new GamePlayer("张三");
//定义一个代练
IGamePlayer proxy = new GamePlayerProxy(player);
//开始打游戏
System.out.println("开始时间是:2017-4-20 10:45");
proxy.login("zhangSan","password");
//开始杀怪
proxy.killBoss();
//升级
proxy.upGrade();
//记录结束游戏时间
System.out.println("结束时间是:2017-4-21 058:34");
}
}
3.动态代理
动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理哪个对象。
动态代理的UML图示如下所示:

上图中的InvocationHandler是JDK提供的动态代理接口,对被代理类的方法进行代理。
示例代码如下所示:
//抽象主题
public interface Subject{
//业务操作
public void doSomething(String str);
}
//真实主题
public class RealSubject implements Subject{
//业务操作
public void doSomething(String str){
System.out.println("do something!-->"+str);
}
}
//动态代理的Handler类
public class MyInvocationHandler implements InvocationHandler{
//被代理的对象
private Object target = null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object obj){
this.target = obj;
}
//代理方法
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
//执行被代理的方法
return method.invoke(this.target,args);
}
}
//动态代理类
public class DynamicProxy<T>{
public static<T> T newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){
//寻找JoinPoint连接点,AOP框架使用元数据定义
if(true){
//执行一个前置通知
(new BeforeAdvice()).exec();
}
//执行目标,并返回结果
return (T)Proxy.newProxyInstance(loader,interfaces,h);
}
}
//通知接口及实现
public interface IAdvice{
//通知只有一个方法,执行即可
public void exec();
}
public class BeforeAdvice implements IAdvice{
public void exec(){
System.out.println("我是前置通知,我被执行了!");
}
}
//场景类
public class Client{
public static void main(String[] args){
//定义一个主题
Subject subject = new RealSubject();
//定义一个Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定义主题的代理
Subject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(),
subject.getClass().getInterfaces(),
handler);
//代理的行为
proxy.doSomething("Finish");
}
}
//具体业务的动态代理
public class SubjectDynamicProxy extends DynamicProxy{
public static<T> newProxyInstance(Subject subject){
//获得ClassLoader
ClassLoader loader = subject.getClass().getClassLoader();
//获得接口数组
Class<?>[] classes = subject.getClass().getInterfaces();
//获得Handler
InvocationHandler handler = new MyInvocationHandler(subject);
return newProxyInstance(loader,classes,handler);
}
}
//场景类
public class Client{
public static void main(String[] args){
//定义一个主题
Subject subject = new RealSubject();
//定义主题的代理
Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);
//代理的行为
proxy.doSomething("Finish");
}
}
欢迎大家关注我的微信公众号

网友评论