理解并使用设计模式,可以培养咱们良好的面向对象编程习惯,同时在实际应用中,能够如鱼得水,享受游刃有余的乐趣。
Proxy是比较有用途的一种模式,并且变种较多,应用场合覆盖从小结构到整个系统的大结构,Proxy是代理的意思,咱们也许有代理服务器等概念,代理概念能够解释为:在出发点到目的地之间有一道中间层,意为代理。
设计模式中定义:为其余对象提供一种代理以控制对这个对象的访问。html
举例两个具体状况:数据库
总之原则是,对于开销很大的对象,只有在使用它时才建立,这个原则能够为咱们节省不少宝贵的Java内存。因此,有些人认为Java耗费资源内存,我觉得这和程序编制思路也有必定的关系。编程
以Jive论坛系统为例,访问论坛系统的用户有多种类型:注册普通用户、论坛管理者、系统管理者、游客。注册普通用户才能发言,论坛管理者能够管理他被受权的论坛,系统管理者能够管理全部事务等,这些权限划分和管理是使用Proxy完成的。
Forum是Jive的核心接口,在Forum中陈列了有关论坛操做的主要行为,如论坛名称,论坛描述的获取和修改,帖子发表删除编辑等。
在ForumPermissions中定义了各类级别权限的用户:设计模式
public class ForumPermissions implements Cacheable { /** * Permission to read object. */ public static final int READ = 0; /** * Permission to administer the entire sytem. */ public static final int SYSTEM_ADMIN = 1; /** * Permission to administer a particular forum. */ public static final int FORUM_ADMIN = 2; /** * Permission to administer a particular user. */ public static final int USER_ADMIN = 3; /** * Permission to administer a particular group. */ public static final int GROUP_ADMIN = 4; /** * Permission to moderate threads. */ public static final int MODERATE_THREADS = 5; /** * Permission to create a new thread. */ public static final int CREATE_THREAD = 6; /** * Permission to create a new message. */ public static final int CREATE_MESSAGE = 7; /** * Permission to moderate messages. */ public static final int MODERATE_MESSAGES = 8; ..... public boolean isSystemOrForumAdmin() { return (values[FORUM_ADMIN] || values[SYSTEM_ADMIN]); } ..... }
所以,Forum中各类操做权限是和ForumPermissions定义的用户级别有关系的,做为接口Forum的实现:ForumProxy正是将这种对应关系联系起来。好比,修改Forum的名称,只有论坛管理者或系统管理者能够修改,代码以下:浏览器
public class ForumProxy implements Forum { private ForumPermissions permissions; private Forum forum; this.authorization = authorization; public ForumProxy(Forum forum, Authorization authorization, ForumPermissions permissions){ this.forum = forum; this.authorization = authorization; this.permissions = permissions; } ..... public void setName(String name) throws UnauthorizedException, ForumAlreadyExistsException{ //只有是系统或论坛管理者才能够修更名称 if (permissions.isSystemOrForumAdmin()) { forum.setName(name); } else { throw new UnauthorizedException(); } } ... }
而DbForum才是接口Forum的真正实现,以修改论坛名称为例:安全
public class DbForum implements Forum, Cacheable { ... public void setName(String name) throws ForumAlreadyExistsException { .... this.name = name; //这里真正将新名称保存到数据库中 saveToDb(); .... } ... }
凡是涉及到对论坛名称修改这一事件,其余程序都首先得和ForumProxy打交道,由ForumProxy决定是否有权限作某同样事情,ForumProxy是个名副其实的"网关","安全代理系统"。
在平时应用中,无可避免总要涉及到系统的受权或安全体系,无论你有无心识的使用Proxy,实际你已经在使用Proxy了。
咱们继续结合Jive谈入深一点,下面要涉及到工厂模式了。
咱们已经知道,使用Forum须要经过ForumProxy,Jive中建立一个Forum是使用Factory模式,有一个总的抽象类ForumFactory,在这个抽象类中,调用ForumFactory是经过getInstance()方法实现,这里使用了Singleton(也是设计模式之一),getInstance()返回的是ForumFactoryProxy。
为何不返回ForumFactory,而返回ForumFactory的实现ForumFactoryProxy?缘由是明显的,须要经过代理肯定是否有权限建立forum。
在ForumFactoryProxy中咱们看到代码以下:服务器
public class ForumFactoryProxy extends ForumFactory { protected ForumFactory factory; protected Authorization authorization; protected ForumPermissions permissions; public ForumFactoryProxy(Authorization authorization, ForumFactory factory,ForumPermissions permissions){ this.factory = factory; this.authorization = authorization; this.permissions = permissions; } public Forum createForum(String name, String description) throws UnauthorizedException, ForumAlreadyExistsException{ //只有系统管理者才能够建立forum if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) { Forum newForum = factory.createForum(name, description); return new ForumProxy(newForum, authorization, permissions); } else { throw new UnauthorizedException(); } } }
方法createForum返回的也是ForumProxy,Proxy就象一道墙,其余程序只能和Proxy交互操做。
注意到这里有两个Proxy:ForumProxy和ForumFactoryProxy。表明两个不一样的职责:使用Forum和建立Forum。至于为何将使用对象和建立对象分开,这也是为何使用Factory模式的缘由所在:是为了"封装" "分派"。换句话说,尽量功能单一化,方便维护修改。
Jive论坛系统中其余如帖子的建立和使用,都是按照Forum这个思路而来的。
以上咱们讨论了如何使用Proxy进行受权机制的访问,Proxy还能够对用户隐藏另一种称为copy-on-write的优化方式。拷贝一个庞大而复杂的对象是一个开销很大的操做,若是拷贝过程当中,没有对原来的对象有所修改,那么这样的拷贝开销就没有必要。用代理延迟这一拷贝过程。
好比:咱们有一个很大的Collection,具体如hashtable,有不少客户端会并发同时访问它。其中一个特别的客户端要进行连续的数据获取,此时要求其余客户端不能再向hashtable中增长或删除 东东。
最直接的解决方案是:使用collection的lock,让这特别的客户端得到这个lock,进行连续的数据获取,而后再释放lock。网络
public void foFetches(Hashtable ht){ synchronized(ht){ //具体的连续数据获取动做.. } }
可是这一办法可能锁住Collection会很长时间,这段时间,其余客户端就不能访问该Collection了。
第二个解决方案是clone这个Collection,而后让连续的数据获取针对clone出来的那个Collection操做。这个方案前提是,这个Collection是可clone的,并且必须有提供深度clone的方法。Hashtable就提供了对本身的clone方法,但不是Key和value对象的clone。并发
public void foFetches(Hashtable ht){ Hashttable newht=(Hashtable)ht.clone(); }
问题又来了,因为是针对clone出来的对象操做,若是原来的母体被其余客户端操做修改了,那么对clone出来的对象操做就没有意义了。
最后解决方案:咱们能够等其余客户端修改完成后再进行clone,也就是说,这个特别的客户端先经过调用一个叫clone的方法来进行一系列数据获取操做。但实际上没有真正的进行对象拷贝,直至有其余客户端修改了这个对象Collection。
使用Proxy实现这个方案,这就是copy-on-write操做。
Proxy应用范围很广,如今流行的分布计算方式RMI和Corba等都是Proxy模式的应用。编辑器
系列文章:
Java设计模式(5)共享模式/享元模式(Flyweight模式)
Java设计模式(14)责任链模式(Chain of Responsibility模式)