在我们公司内部,是不能上youku,土豆这些网站的。他是怎么做到的呢? 相信大部分人都知道,公司内网上网需要用代理,引出来今天的复习内容:代理模式。
代码模式的定义是:为其他对象提供 一种代理以控制对这个对象的访问。
代理模式是在实际请求方(客户端)和请求响应方(服务端)增加了一层中转站,可以实现额外的功能。最常见的代理就是公司内网访问外网的代理(比如第一段的场景),这种情况一般是为了权限控制(权限控制用代理比较合适,又比如用户登录时候的权限分配,也可以用代理)。还有就是自己不能访问服务端(比如在大陆访问facebook),只能去求助代理(主要负责绕过防火墙)。
上代码:
首先,抽象角色接口:(服务提供方提供的接口)
/** * AbSubject:抽象角色接口 * @author xuejupo [email protected] * create in 2015-12-23 上午9:11:07 * */ interface AbSubject{ public void request(String url); }
真实角色接口(真正的服务提供方):
/** * RealSubject:真实角色类,上网就靠他了 * @author xuejupo [email protected] * create in 2015-12-23 上午9:10:54 * */ class RealSubject implements AbSubject{ public RealSubject(){ } public void request(String url){ System.out.println("您打开了网址:"+url); } }
代理接口:
/** * AbProxy: 代理接口 * @author xuejupo [email protected] * create in 2015-12-23 上午9:21:45 * */ interface AbProxy extends AbSubject{ public void addBlackUrl(String url); }
代理类:
/** * SubProxy:代理类 * @author xuejupo [email protected] * create in 2015-12-23 上午9:10:47 * */ class SubProxy implements AbProxy{ /** * @Fields blackList : 定义上网黑名单 */ private List<String> blackList = new ArrayList<String>(); private AbSubject thisSub; public SubProxy(AbSubject thisSub){ this.thisSub = thisSub; } @Override public void request(String url) { // TODO Auto-generated method stub if(this.blackList.contains(url)){ System.out.println("小子,你想看啥呢,到我办公室来一趟!"); return; } thisSub.request(url); } /** * addBlackUrl: 增加黑名单 * void 返回类型 */ public void addBlackUrl(String url){ this.blackList.add(url); } }
很简单的一个代理,就像第一段的场景,用黑名单过滤网址。
测试类:
public static void main(String[] arg){ AbSubject real = new RealSubject(); //定义上网代理 AbProxy proxy = new SubProxy(real); //先看会优酷 System.out.println("先看会优酷"); proxy.request("youku.com"); //把优酷加入到黑名单中 System.out.println("把优酷加入到黑名单中"); proxy.addBlackUrl("youku.com"); //还敢看优酷? proxy.request("youku.com"); }
测试结果:
先看会优酷 您打开了网址:youku.com 把优酷加入到黑名单中 小子,你想看啥呢,到我办公室来一趟!
上面代码还有一个问题,好像上网也不需要代理呀。。 设计模式之禅上有哥强制代理模式,代码如下:
/** * AbstractSubject:抽象角色接口 * @author xuejupo [email protected] * create in 2015-12-23 上午9:11:07 * */ interface AbstractSubject{ public void request(String url); public AbsProxy getProxy(); } /** * Subject:真是角色类,上网就靠他了 * @author xuejupo [email protected] * create in 2015-12-23 上午9:10:54 * */ class Subject implements AbstractSubject{ private AbsProxy proxy = null; public Subject(){ } public void request(String url){ if(this.proxy == null){ System.out.println("不用代理不能上网!"); }else{ System.out.println("您打开了网址:"+url); } } @Override public AbsProxy getProxy() { // TODO Auto-generated method stub //设置代理 this.proxy = new RealProxy(this); return this.proxy; } } /** * AbsProxy: 代理接口 * @author xuejupo [email protected] * create in 2015-12-23 上午9:21:45 * */ interface AbsProxy extends AbstractSubject{ public void addBlackUrl(String url); } /** * RealProxy:代理类 * @author xuejupo [email protected] * create in 2015-12-23 上午9:10:47 * */ class RealProxy implements AbsProxy{ /** * @Fields blackList : 定义上网黑名单 */ private List<String> blackList = new ArrayList<String>(); private AbstractSubject thisSub; public RealProxy(AbstractSubject thisSub){ this.thisSub = thisSub; } @Override public void request(String url) { // TODO Auto-generated method stub if(this.blackList.contains(url)){ System.out.println("小子,你想看啥呢,到我办公室来一趟!"); return; } thisSub.request(url); } /** * addBlackUrl: 增加黑名单 * void 返回类型 */ public void addBlackUrl(String url){ this.blackList.add(url); } @Override public AbsProxy getProxy() { // TODO Auto-generated method stub return this; } }
测试类:
public class ForceProxy { public static void main(String[] arg){ AbstractSubject real = new Subject(); //我想自己上网,不通过代理 System.out.println("不通过代理上网:"); real.request("youku.com"); //只能通过代理上网: System.out.println("那就用代理吧:"); AbsProxy proxy = real.getProxy(); //先看会优酷 System.out.println("先看会优酷:"); proxy.request("youku.com"); } }
结果:
不通过代理上网: 不用代理不能上网! 那就用代理吧: 先看会优酷: 您打开了网址:youku.com
可以看到,是比较符合第一段的场景的。
个人总结:
这样做的好处是什么? 为什么要用代理? 个人觉得,还是解耦。对于我们个人来说,用代理好像更麻烦,但是对于大型项目来说,可能一个接口对应的使用方不止一个人,而且接口的开发团队可能跟你不是一个组的,甚至不是一个公司的,所以要修改接口或者扩展接口太难了。。 代理模式的设定就是,代理类的扩展和修改,要远远简单与不用代理的扩展和修改。
软件工程中一个很大的忌讳就是修改已经上线并且正常运行中的代码。
有一种场景就是,接口已经上线了,你需要用到接口,但是需要稍稍修改下接口,比如说第一段的场景中,我们老总想看优酷怎么办? 上网的接口已经写完并且正常在线上运行,不能修改,万一修改出错影响太大,这种情况太适合用代理了,修改一下代理,甚至给老大单独开一个代理都行,让他看去吧!