定义:为其余对象提供一种代理以控制对这个对象的访问。在某些状况下,一个对象不适合或者不能直接引用另外一个对象,而代理对象能够在客户端和目标对象之间起到中介的做用。一个类表明另外一个类的功能。这种类型的设计模式属于结构型模式。java
意图:为其余对象提供一种代理以控制对这个对象的访问。spring
主要解决:在直接访问对象时带来的问题,好比说:要访问的对象在远程的机器上。在面向对象系统中,有些对象因为某些缘由(好比对象建立开销很大,或者某些操做须要安全控制,或者须要进程外的访问),直接访问会给使用者或者系统结构带来不少麻烦,咱们能够在访问此对象时加上一个对此对象的访问层。设计模式
应用实例:一、Windows 里面的快捷方式。二、买火车票不必定在火车站买,也能够去代售点。 三、spring aop。安全
优势: 一、职责清晰。ide
被代理对象只负责本身实际的业务逻辑,不关心其余非自己的职责。并将其余事务能够经过代理类处理。测试
二、高扩展性。this
不管被代理对象如何改变,只要代理类和被代理类都实现了统一接口,都不一样修改代理类,并且即便扩展了新的被代理类,代理类也可使用,只要建立代理类的时候传入对应的被代理类对象。spa
三、智能化。设计
这主要体如今动态代理中,下面会讲解动态代理。若是有兴趣了解Spring的AOP,其实就是使用了动态代理。3d
缺点: 一、因为在客户端和真实主题之间增长了代理对象,所以有些类型的代理模式可能会形成请求的处理速度变慢。
二、实现代理模式须要额外的工做,有些代理模式的实现很是复杂。
注意事项: 一、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
二、和装饰器模式的区别:装饰器模式为了加强功能,而代理模式是为了加以控制。
咱们举个示例,好比在娱乐圈,客户与艺人进行商业合做,通常都不是与艺人直接联系,签定时间、地点、薪酬等合同,而是
找艺人的经纪人商讨,那么这里商艺活动就是抽象对象(主题),艺人就被代理对象,经纪人就是代理对象。
代码示例:
package com.pattern.proxy1; /** * 抽象接口 演艺 */ public interface Performance { public void Sing(String name, String address, String date);//谁在哪一个时间哪一个地点唱歌 public void dance(String name, String address, String date); //谁在哪一个时间哪一个地点跳舞 public void perform(String name, String address, String date);//谁在哪一个时间哪一个地点表演 }
package com.pattern.proxy1; /** * 被代理对象 艺人 */ public class Artist implements Performance { @Override public void Sing(String name, String address, String date) { System.out.println(date+" "+name +"在"+address +"rap了一首xX"); } @Override public void dance(String name, String address, String date) { System.out.println( date+" "+name +"在"+address +"跳了一个芭蕾"); } @Override public void perform(String name, String address, String date) { System.out.println(date+" "+name +"在"+address +"表演了打篮球"); } }
package com.pattern.proxy1; /** * 代理对象 经纪人 * Created by wanbf on 2019/5/26. */ public class Agent implements Performance { //保存被代理人的实例 private Performance performance; public Agent(Performance performance){ this.performance = performance; } @Override public void Sing(String name, String address, String date) { System.out.println("经济人和客户肯定时间地点等一系列细节后..."); performance.Sing(name,address,date);//这里经纪人是不会唱歌的,执行艺人的唱歌 下同 } @Override public void dance(String name, String address, String date) { System.out.println("经济人和客户肯定时间地点等一系列细节后..."); performance.dance(name,address,date); } @Override public void perform(String name, String address, String date) { System.out.println("经济人和客户肯定时间地点等一系列细节后..."); performance.perform(name,address,date); } }
package com.pattern.proxy1; import java.text.DateFormat; import java.util.Date; /** * Created by wanbf on 2019/5/26. 这里是最基本代理模式示例 */ public class Main { public static void consumer(Performance performance){ performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date())); performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date())); performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date())); } public static void main(String[] args){ consumer(new Artist()); System.out.println("----------------"); consumer(new Agent(new Artist())); } }
输出: 2019-5-27 CXK在韩国rap了一首xX 2019-5-27 CXK在韩国跳了一个芭蕾 2019-5-27 CXK在韩国表演了打篮球 ---------------- 经济人和客户肯定时间地点等一系列细节后... 2019-5-27 CXK在韩国rap了一首xX 经济人和客户肯定时间地点等一系列细节后... 2019-5-27 CXK在韩国跳了一个芭蕾 经济人和客户肯定时间地点等一系列细节后... 2019-5-27 CXK在韩国表演了打篮球
从示例中咱们能够看出 客户直接调用 被代理人对象 和 代理人对象的区别在于一些额外的操做从 “实际”对象中 分离到不一样的地方,特别是当你可以很容易的作出修改,从没有额外操做转为使用这些操做。
那么在示例中客户(抽象对象、主题接口)想要的只是艺人的表演,而艺人(被代理对象)只管表演,那么其中一些好比时间地点细节操做 交给经纪人(代理对象) 去完成,而后在调用艺人去完成表演。
在实际项目中,额外的操做多数是日志记录操做。
package com.pattern.proxy2; /** * 抽象接口 演艺 */ public interface Performance { public void Sing(String name, String address, String date);//谁在哪一个时间哪一个地点唱歌 public void dance(String name, String address, String date); //谁在哪一个时间哪一个地点跳舞 public void perform(String name, String address, String date);//谁在哪一个时间哪一个地点表演 }
package com.pattern.proxy2; /** * 被代理对象 艺人 */ public class Artist implements Performance { //经过构造方法将代理传进来 public Artist( Performance performance) { if (performance == null){ System.out.println("不是经过代理人进来的"); } } @Override public void Sing(String name, String address, String date) { System.out.println(date+" "+name +"在"+address +"rap了一首xX"); } @Override public void dance(String name, String address, String date) { System.out.println( date+" "+name +"在"+address +"跳了一个芭蕾"); } @Override public void perform(String name, String address, String date) { System.out.println(date+" "+name +"在"+address +"表演了打篮球"); } }
package com.pattern.proxy2; /** * 代理对象 经纪人 * Created by wanbf on 2019/5/26. */ public class Agent implements Performance { //保存被代理人的实例 private Performance performance; public Agent(){ //经过构造方法建立 Artist,将本身传递出去 this.performance = new Artist(this); } @Override public void Sing(String name, String address, String date) { System.out.println("经济人和客户肯定时间地点等一系列细节后..."); performance.Sing(name,address,date);//这里经纪人是不会唱歌的,执行艺人的唱歌 下同 } @Override public void dance(String name, String address, String date) { System.out.println("经济人和客户肯定时间地点等一系列细节后..."); performance.dance(name,address,date); } @Override public void perform(String name, String address, String date) { System.out.println("经济人和客户肯定时间地点等一系列细节后..."); performance.perform(name,address,date); } }
package com.pattern.proxy2; import java.text.DateFormat; import java.util.Date; /** * Created by wanbf on 2019/5/26. 这里是普通代理模式示例 */ public class Main { public static void consumer(Performance performance){ performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date())); performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date())); performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date())); } public static void main(String[] args){ Performance performance = new Agent(); consumer(performance); System.out.println("----------------"); // consumer(new Agent(new Artist())); } }
输出: 经济人和客户肯定时间地点等一系列细节后... 2019-5-27 CXK在韩国rap了一首xX 经济人和客户肯定时间地点等一系列细节后... 2019-5-27 CXK在韩国跳了一个芭蕾 经济人和客户肯定时间地点等一系列细节后... 2019-5-27 CXK在韩国表演了打篮球 ----------------
从测试代码能够看出,咱们调用 是用知道被代理对象 真实角色是谁的,只有代理对象知道,那么屏蔽了真实角色的变动 对整个模块的影响。
package com.pattern.proxy; /** * 抽象接口 演艺 */ public interface Performance { public void Sing(String name , String address, String date);//谁在哪一个时间哪一个地点唱歌 public void dance(String name , String address, String date); //谁在哪一个时间哪一个地点跳舞 public void perform(String name , String address, String date);//谁在哪一个时间哪一个地点表演 }
package com.pattern.proxy; /** * 被代理对象 艺人 */ public class Artist implements Performance{ private Agent agent;// 获取指定代理人对象 //获取指定的代理人对象 public Performance getAgent(){ agent = new Agent(this); return agent; } @Override public void Sing(String name, String address, String date) { if (agent == null){ System.out.println("请使用指定的代理类"); }else System.out.println(date+" "+name +"在"+address +"rap了一首xX"); } @Override public void dance(String name, String address, String date) { if (agent == null){ System.out.println("请使用指定的代理类"); }else System.out.println( date+" "+name +"在"+address +"跳了一个芭蕾"); } @Override public void perform(String name, String address, String date) { if (agent == null){ System.out.println("请使用指定的代理类"); }else System.out.println(date+" "+name +"在"+address +"表演了打篮球"); } }
package com.pattern.proxy; /** * 代理对象 经纪人 * Created by wanbf on 2019/5/26. */ public class Agent implements Performance{ //保存被代理人的实例 private Performance performance; public Agent(Performance performance){ this.performance = performance; } @Override public void Sing(String name, String address, String date) { performance.Sing(name,address,date);//这里经纪人是不会唱歌的,执行艺人的唱歌 下同 } @Override public void dance(String name, String address, String date) { performance.dance(name,address,date); } @Override public void perform(String name, String address, String date) { performance.perform(name,address,date); } }
public static void main(String[] args){ Performance performance = new Artist().getAgent(); performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date())); performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date())); performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date())); } 输出: 2019-5-26 CXK在韩国rap了一首xX 2019-5-26 CXK在韩国跳了一个芭蕾 2019-5-26 CXK在韩国表演了打篮球
上面咱们是走指定的代理对象 执行方法;
那么咱们不经过代理方法来执行呢,
//不经过代理还执行 Performance performance = new Artist(); performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date())); performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date())); performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date())); 输出: 请使用指定的代理类 请使用指定的代理类 请使用指定的代理类
很显然,不用代理方法是不能执行成功的
不是指定代理方法呢,
//不是指定的代理方法 Performance performance = new Agent(new Artist()); performance.Sing("CXK","韩国", DateFormat.getDateInstance().format(new Date())); performance.dance("CXK","韩国",DateFormat.getDateInstance().format(new Date())); performance.perform("CXK","韩国",DateFormat.getDateInstance().format(new Date())); 输出: 请使用指定的代理类 请使用指定的代理类 请使用指定的代理类
显然不是指定的代理方法也是执行不了的
这个示例是强制代理模式,概念就是要从真是角色那里查找到代理角色,不容许直接访问真实角色。
上层模块只须要调用Agent()获取代理来访问真实角色的全部方法,它根本就不须要产生一个代理角色,代理的管理已经由真实角色本身来完成。
后续讲解一个 虚拟代理模式 和动态代理模式。