代理模式
代理模式是一个使用率非常高的模式,其定义如下:Provide a surrogate or placeholder for another object to control access to it.(为其他对象提供一种代理以控制对这个对象的访问。)
代理模式在各类开发中运用的相当广泛,不论是j2ee,android还是ios,都能看到它的身影,所以说设计模式无处不在。代理模式,字面理解就是自己不方便做或者不能做的事情,需要第三方代替来做,最终通过第三方来达到自己想要的目的或效果。举例了:员工小李在B总公司打工,B总成天让小李加班不给加班费,小李忍受不住了,就想去法院告B总。虽然法律上允许打官司不请律师,允许自辩。但是小李第一不熟悉法律起诉的具体流程,第二嘴比较笨,人一多腿就抖得厉害。因此,小李决定去找律师帮忙打官司。找律师打官司和自己打官司相比,有相同的地方,也有不同的地方。
相同的地方
1.都需要提交原告的资料,如姓名、年龄、事情缘由、想达到的目的。
2. 都需要经过法院的取证调查,开庭争辩等过程。
3. 最后拿到审判结果。
不同的地方
1、 小李省事了,让专业的人做专业的事,不需要自己再去了解法院那一套繁琐复杂的流程。
2、 把握更大了。
通过上面的例子,我们注意到代理模式有几个重点。
1、 被代理的角色(小李)
2、 代理角色(律师)
3、 协议(不管是代理和被代理谁去做,都需要做的事情,抽象出来就是协议)
下面给个例子
public class Proxy {
public static void main(String[] args) {
Employer employer=new Employer();
System.out.println("我受不了了,我要打官司告老板");
System.out.println("找律师解决一下吧......");
Protocol lawyerProxy=new LawyerProxy(employer);
lawyerProxy.register("Forest");
lawyerProxy.dosomething();
lawyerProxy.notifys();
}
}
interface Protocol{
//登记资料
public void register(String name);
//调查案情,打官司
public void dosomething();
//官司完成,通知雇主
public void notifys();
}
//律师类
class LawyerProxy implements Protocol{
private Employer employer;
public LawyerProxy(Employer employer){
this.employer=employer;
}
@Override
public void register(String name) {
// TODO Auto-generated method stub
this.employer.register(name);
}
public void collectInfo(){
System.out.println("作为律师,我需要根据雇主提供的资料,整理与调查,给法院写出书面文字,并提供证据。");
}
@Override
public void dosomething() {
// TODO Auto-generated method stub
collectInfo();
this.employer.dosomething();
finish();
}
public void finish(){
System.out.println("本次官司打完了...............");
}
@Override
public void notifys() {
// TODO Auto-generated method stub
this.employer.notifys();
}
}
//雇主类
class Employer implements Protocol{
String name=null;
@Override
public void register(String name) {
// TODO Auto-generated method stub
this.name=name;
}
@Override
public void dosomething() {
// TODO Auto-generated method stub
System.out.println("我是'"+this.name+"'要告B总,他每天让我不停的加班,还没有加班费。");
}
@Override
public void notifys() {
// TODO Auto-generated method stub
System.out.println("法院裁定,官司赢了,B总需要赔偿10万元精神补偿费。");
}
}
运行后,打印如下:
我受不了了,我要打官司告老板
找律师解决一下吧……
作为律师,我需要根据雇主提供的资料,整理与调查,给法院写出书面文字,并提供证据。
我是’Forest’要告B总,他每天让我不停的加班,还没有加班费。
本次官司打完了……………
法院裁定,官司赢了,B总需要赔偿10万元精神补偿费。
代码说明:
Protocol这个类就是上面所说的协议,是被代理者或者代理者共同遵守的约定。也就是说,无论是原告还是代理律师,到法院走程序,都需要做的事情。我们抽象出来,这个就是协议。
Employer这类是雇主类也称被代理者类,它遵从Protocol协议,并实现了Protocol协议的三个方法,并去分别完成了具体事情。
LawyerProxy这类是代理类,它也遵从Protocol协议,与Employer不同的是,定义了一个Employer对象,通过构造函数初始化。在实现的三个方法里,分别去调用被代理类的相同实现。就好比去模拟一个被告者,站在被告的角度上,去法院告状。也就是说LawyerProxy代理类对所有想打官司的人开放,只要有原告进来,我就帮他打官司。值得注意的是collectInfo和finish这两个函数,请律师打官司和不请律师打官司,其实都要做同样的事情(register、dosomething、notifys),但是至于为什么?刚才不是说了吗,请律师的好处是省心并且专业,他在做同样的事情前提下,还会收集对你有利的证据和资料(collectInfo),以及后续事情的处理(finish)。
上面就是最普通的代理模式,引申一点,我们看到,对于被告来说,必须创建一个Employer类,并实例化后传参给LawyerProxy代理类,这样做,是不是暴漏了Employer?如果隐藏一下,对于被告来说,更智能傻瓜一点,该怎么做呢?
public class Proxy {
public static void main(String[] args) {
//Employer employer=new Employer();
System.out.println("我受不了了,我要打官司告老板");
System.out.println("找律师解决一下吧......");
Protocol lawyerProxy=new LawyerProxy("Forest");
lawyerProxy.dosomething();
lawyerProxy.notifys();
}
}
interface Protocol{
//登记资料
public void register(String name);
//调查案情,打官司
public void dosomething();
//官司完成,通知雇主
public void notifys();
}
//律师类
class LawyerProxy implements Protocol{
private Employer employer;
public LawyerProxy(String name){
if(name==null) {
System.out.println("谁告状?逗我玩呢吧?");
return;
}
if(employer==null) employer=new Employer();
register(name);
}
@Override
public void register(String name) {
// TODO Auto-generated method stub
this.employer.register(name);
}
public void collectInfo(){
System.out.println("作为律师,我需要根据雇主提供的资料,整理与调查,给法院写出书面文字,并提供证据。");
}
@Override
public void dosomething() {
// TODO Auto-generated method stub
collectInfo();
this.employer.dosomething();
finish();
}
public void finish(){
System.out.println("本次官司打完了...............");
}
@Override
public void notifys() {
// TODO Auto-generated method stub
this.employer.notifys();
}
}
//雇主类
class Employer implements Protocol{
String name=null;
@Override
public void register(String name) {
// TODO Auto-generated method stub
this.name=name;
}
@Override
public void dosomething() {
// TODO Auto-generated method stub
System.out.println("我是'"+this.name+"'要告B总,他每天让我不停的加班,还没有加班费。");
}
@Override
public void notifys() {
// TODO Auto-generated method stub
System.out.println("法院裁定,官司赢了,B总需要赔偿10万元精神补偿费。");
}
}
看到没new LawyerProxy(“Forest”),只需要给代理类传入简单的名字,隐含了Employer类,代理类就会自动去创建一个Employer实例,模拟一个用户继续替你完成打官司的事情。
在这种改造下,系统更加简洁了,调用者只知道代理存在就可以,不用知道代理了谁。
这种模式,调用者只知代理而不用知道真实的角色是谁,屏蔽了真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有任何的影响,只要你实现了接口所对应的方法,这种模式非常适合对扩展性要求较高的场合。当然,在实际的项目中一般都是通过约定来禁止new一个真实的角色,这也是一个非常好的方案
代理模式还有一种就是强制代理,为什么这么说?一般的思维都是通过代理找到真实的角色,但是强制代理却是要“强制”,你必须通过真实角色查找到代理角色,否则你不能访问,不管你是直接new一个主题角色都不能访问,只有通过真实角色指定的代理类才可以访问
例子代码如下
public class Proxy {
public static void main(String[] args) {
// TODO Auto-generated method stub
Employer employer=new Employer();
System.out.println("我受不了了,我要打官司告老板");
System.out.println("找律师解决一下吧......");
Protocol lawyerProxy=new LawyerProxy(employer);
lawyerProxy.register("Forest");
lawyerProxy.dosomething();
lawyerProxy.notifys();
}
}
interface Protocol{
//登记资料
public void register(String name);
//调查案情,打官司
public void dosomething();
//官司完成,通知雇主
public void notifys();
//每个人都露找一下自己的代理
public Protocol getProxy();
}
//律师类
class LawyerProxy implements Protocol{
private Employer employer;
public LawyerProxy(Employer employer){
this.employer = employer;
}
@Override
public void register(String name) {
// TODO Auto-generated method stub
this.employer.register(name);
}
public void collectInfo(){
System.out.println("作为律师,我需要根据雇主提供的资料,整理与调查,给法院写出书面文字,并提供证据。");
}
@Override
public void dosomething() {
// TODO Auto-generated method stub
collectInfo();
this.employer.dosomething();
finish();
}
public void finish(){
System.out.println("本次官司打完了...............");
}
@Override
public void notifys() {
// TODO Auto-generated method stub
this.employer.notifys();
}
@Override
public Protocol getProxy() {
// TODO Auto-generated method stub
return this;
}
}
//雇主类
class Employer implements Protocol{
String name = null;
private Protocol proxy = null;
@Override
public void register(String name) {
// TODO Auto-generated method stub
this.name = name;
}
@Override
public void dosomething() {
// TODO Auto-generated method stub
if(isProxy()){
System.out.println("我是'"+this.name+"'要告B总,他每天让我不停的加班,还没有加班费。");
}else{
System.out.println("请用代理模式访问");
}
}
@Override
public void notifys() {
// TODO Auto-generated method stub
if(isProxy()){
System.out.println("法院裁定,官司赢了,B总需要赔偿10万元精神补偿费。");
}else{
System.out.println("请用代理模式访问");
}
}
@Override
public Protocol getProxy() {
// TODO Auto-generated method stub
this.proxy = new LawyerProxy(this);
return this.proxy;
}
//校验是否是代理访问
private boolean isProxy(){
if(this.proxy == null){
return false;
}else{
return true;
}
}
}
执行的结果你会发现提示你“使用代理模式访问”
原因在开始的时候已经说过了,在这里我们只需要在main方法里修改一些即可
public static void main(String[] args) {
// TODO Auto-generated method stub
Employer employer=new Employer();
System.out.println("我受不了了,我要打官司告老板");
System.out.println("找律师解决一下吧......");
Protocol lawyerProxy=employer.getProxy();
lawyerProxy.register("Forest");
lawyerProxy.dosomething();
lawyerProxy.notifys();
}
最后做个总结:
代理模式的优点:
*职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事物,通过后期的代理完成一件事物,附带的结果就是变成简介清晰。
*高扩展性
具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不出接口,那我们的代理类完全就可以在不做任务修改的情况下使用。