




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、2 Jive与设计模式Jive论坛系统使用大量设计模式巧妙地实现了一系列功能。因为设计模式的通用性和可理解性,将帮助更多人很快地理解 Jive论坛源码,从而可以依据一种“协定”来动态地扩展它。那么使用设计模式还有哪些好处?2.1 设计模式设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的。设计模式使代码编制真正工程化,设计模式是软件工程的基石。GOF(设计模式作者简称)设计模式这本书第一次将设计模式提升到理论高度,并将之规范化,该书
2、提出了23种基本设计模式。自此,在可复用面向对象软件的发展过程中,新的大量的设计模式不断出现。很多人都知道Java是完全面向对象的设计和编程语言,但是由于接受教育以及经验的原因,大多数程序员或设计人员都是从传统的过程语言转变而来,因此在思维习惯上要完全转变为面向对象的设计和开发方式是困难的,而学习设计模式可以更好地帮助和坚固这种转变。凡是学习完成设计模式的人都有一种类似重生的感觉,这种重生可以从很多方面去解释。换一种新的角度来看待和解决问题应该是一种比较贴切的解释,而这种新的思维角度培养属于基础培训,因此,设计模式是学习Java的必读基础课程之一。由于设计模式概念比较抽象,对于初学者学习有一定
3、的难度,因此结合Jive论坛系统学习设计模式将是一种很好的选择。掌握了设计模式,将会帮助程序员或设计人员以更加可重用性、可伸缩性的眼光来开发应用系统,甚至开发通用的框架系统。框架系统是构成一类特定软件可复用设计的一组相互协作的类,主要是对应用系统中反复重用部分的提炼,类似一种模板,这是一种结构性的模板。框架通常定义了应用体系的整体结构、类和对象的关系等设计参数,以便于具体应用实现者能集中精力于应用本身的特定细节。框架强调设计复用,而设计模式最小的可重用单位,因此框架不可避免地会反复使用到设计模式。关于通用框架系统的设计开发将在以后章节中讨论。其实Jive论坛本身也形成了一个基于Web结构的通用
4、框架系统,因为它很多设计思想是可以重用的,例如设定一个总体入口,通过入口检查用户的访问控制权限,当然还有其他各方面的功能实现方式都是值得在其他系统中借鉴的,也正因为它以模式的形式表现出来,这种可重用性和可借鉴性就更强。2.2 ForumFactory与工厂模式工厂模式是GOF设计模式的主要常用模式,它主要是为创建对象提供了一种接口,工厂模式主要是封装了创建对象的细节过程,从而使得外界调用一个对象时,根本无需关心这个对象是如何产生的。在GOF设计模式中,工厂模式分为工厂方法模式和抽象工厂模式。两者主要区别是,工厂方法是创建一种产品接口下的产品对象,而抽象工厂模式是创建多种产品接口下的
5、产品对象,非常类似Builder生成器模式。在平时实践中,使用较多的基本是工厂方法模式。以类SampleOne为例,要创建SampleOne的对象实例:SampleOne sampleOne = new SampleOne();如果Sample类有几个相近的类:SampleTwo或SampleThree,那么创建它们的实例分别是:SampleTwo sampleTwo = new SampleTwo();SampleThree sampleThree = new SampleThree();其实这3个类都有一些共同的特征,如网上商店中销售书籍、玩具或者化妆品。虽然它们是不同的具体产品,但是它们
6、有一个共同特征,可以抽象为“商品”。日常生活中很多东西都可以这样高度抽象成一种接口形式。上面这3个类如果可以抽象为一个统一接口SampleIF,那么上面语句就可以成为:SampleIF sampleOne = new SampleOne();SampleIF sampleTwo = new SampleTwo();SampleIF sampleThree = new SampleThree();在实际情况中,有时并不需要同时生成3种对象,而是根据情况在3者之中选一个。在这种情况下,需要使用工厂方法来完成了,创建一个叫SampleFactory的抽象类:public class SampleFa
7、ctory public abstract SampleIF creator();在这个抽象工厂类中有一个抽象方法creator,但是没有具体实现,而是延迟到它的子类中实现,创建子类SampleFactoryImp:public class SampleFactoryImp extends SampleFactory public SampleIF creator() /根据其他因素综合判断返回具体产品 /假设应该返回SampleOne对象
8、 return new SampleOne();在SampleFactoryImp中根据具体情况来选择返回SampleOne、SampleTwo或SampleThree。所谓具体情况有很多种:上下文其他过程计算结果;直接根据配置文件中配置。上述工厂方法模式中涉及到一个抽象产品接口Sample,如果还有其他完全不同的产品接口,如Product等,一个子类SampleFactoryImp只能实现一套系列产品方案的生产,如果还需要另外一套系统产品方案,就可能需要另外一个子类SampleFactoryImpTwo来实现。这样,多个产品系列、多个工厂方法就形成了抽象工
9、厂模式。前面已经讨论在Jive中设置了论坛统一入口,这个统一入口就是ForumFactory,以下是ForumFactory的主要代码:public abstract class ForumFactory private static Object initLock = new Object();private static String className = " com.Yasna.forum.database.DbForumFactory"private static ForumFactory factory = null; public s
10、tatic ForumFactory getInstance(Authorization authorization) if (authorization = null) return null;/以下使用了Singleton 单态模式,将在2.3节讨论if (factory = null) synchronized(initLock) if (factory = null) . /从配置文件中获得当前classNametry /动态装载类Class c = Class.forName(className);factory = (ForumFactory)c.newInstance();cat
11、ch (Exception e) return null;/返回 proxy.用来限制授权对forum的访问return new ForumFactoryProxy(authorization, factory,factory.getPermissions(authorization);/创键产品接口Forum的具体对象实例public abstract Forum createForum(String name, String description)throws UnauthorizedException, ForumAlreadyExistsException;
12、/创键产品接口ForumThread的具体对象实例public abstract ForumThread createThread(ForumMessage rootMessage) throws UnauthorizedException;/创键产品接口ForumMessage的具体对象实例 public abstract ForumMessage createMessage();.ForumFactory中提供了很多抽象方法如createForum、createThread和createMessage()等,它们是创建各自产品接口
13、下的具体对象,这3个接口就是前面分析的基本业务对象Forum、ForumThread和ForumMessage,这些创建方法在ForumFactory中却不立即执行,而是推迟到ForumFactory子类中实现。ForumFactory的子类实现是com.Yasna.forum.database.DbForumFactory,这是一种数据库实现方式。即在DbForumFactory中分别实现了在数据库中createForum、createThread和createMessage()等3种方法,当然也提供了动态扩展到另外一套系列产品的生产方案的可能。如果使用XML来实现,那么可以编制一个XmlF
14、orumFactory的具体工厂子类来分别实现3种创建方法。因此,Jive论坛在统一入口处使用了抽象工厂模式来动态地创建论坛中所需要的各种产品,如图3-4所示。图3-4 ForumFactory抽象工厂模式图图3-4中,XmlForumFactory和DbForumFactory作为抽象工厂ForumFactory的两个具体实现,而Forum、ForumThread和ForumMessage分别作为3个系列抽象产品接口,依靠不同的工厂实现方式,会产生不同的产品对象。从抽象工厂模式去理解Jive论坛统一入口处,可以一步到位掌握了几个类之间的大概关系。因为使用了抽象工厂模式这种通用的设
15、计模式,可以方便源码阅读者快速地掌握整个系统的结构和来龙去脉,图3-4这张图已经初步展示了Jive的主要框架结构。细心的读者也许会发现,在上面ForumFactory有一个getInstance比较令人费解,这将在2.3节进行讨论。2.3 统一入口与单态模式在上面ForumFactory的getInstance方法使用单态(SingleTon)模式。单态模式是保证一个类有且仅有一个对象实例,并提供一个访问它的全局访问点。前面曾提到ForumFactory是Jive提供客户端访问数据库系统的统一入口。为了保证所有的客户端请求都要经过这个ForumFactory,如果不使用单态模式,客
16、户端下列调用语句表示生成了ForumFactory实例:ForumFactory factory = new DbForumFactory();客户端每发生一次请求都调用这条语句,这就会发生每次都生成不同factory对象实例,这显然不符合设计要求,因此必须使用单态模式。一般在Java实现单态模式有几种选择,最常用而且安全的用法如下:public class Singleton private Singleton()/在自己内部定义自己一个实例,是不是很奇怪/注意这是private,只供内部调用private static Singleton instance = new Singleton(
17、); /这里提供了一个供外部访问本class的静态方法,可以直接访问public static Singleton getInstance() return instance; 单态模式一共使用了两条语句实现:第一条直接生成自己的对象,第二条提供一个方法供外部调用这个对象,同时最好将构造函数设置为private,以防止其他程序员直接使用new Singleton生成实例。还有一种Java单态模式实现:public class Singleton private Singleton()private static Singleton instance = null; public static
18、synchronized Singleton getInstance() if (instance=null)instancenew Singleton() return instance; 在上面代码中,使用了判断语句。如果instance为空,再进行实例化,这成为lazy initialization。注意getInstance()方法的synchronized,这个synchronized很重要。如果没有synchronized,那么使用getInstance()在第一次被访问时有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及
19、double-checked locking (DCL)的讨论,有兴趣者可以进一步研究。一般认为第一种形式要更加安全些;但是后者可以用在类初始化时需要参数输入的情况下。在Jive的ForumFactory中采取了后者lazy initialization形式,这是为了能够动态配置指定ForumFactory的具体子类。在getInstance中,从配置文件中获得当前工厂的具体实现,如果需要启动XmlForumFactory,就不必修改ForumFactory代码,直接在配置文件中指定className的名字为XmlForumFactory。这样通过下列动态装载机制生成ForumFactory具
20、体对象:Class c = Class.forName(className);factory = (ForumFactory)c.newInstance();这是利用Java的反射机制,可以通过动态指定className的数值而达到生成对象的方式。使用单态模式的目标是为了控制对象的创建,单态模式经常使用在控制资源的访问上。例如数据库连接或Socket连接等。单态模式可以控制在某个时刻只有一个线程访问资源。由于Java中没有全局变量的概念,因此使用单态模式有时可以起到这种作用,当然需要注意是在一个JVM中。2.4 访问控制与代理模式仔细研究会发现,在ForumFactory的getI
21、nstance方法中最后的返回值有些奇怪。按照单态模式的概念应该直接返回factory这个对象实例,但是却返回了ForumFactoryProxy的一个实例,这实际上改变了单态模式的初衷。这样客户端每次通过调用ForumFactory的getInstance返回的就不是ForumFactory的惟一实例,而是新的对象。之所以这样做是为了访问权限的控制,姑且不论这样做的优劣,先看看什么是代理模式。代理模式是属于设计模式结构型模式中一种,它是实际访问对象的代理对象,或者影子对象,主要达到控制实际对象的访问。这种控制的目的很多,例如提高性能等。即远程代理模式,这种模式将在以后章节讨论。其中一个主要的
22、控制目的是控制客户端对实际对象的访问权限。在Jive系统中,因为有角色权限的分别,对于Forum、ForumThread和FroumMessage的访问操作必须经过权限机制验证后才能进行。以ForumFactoryProxy中的createForum方法为例,其实ForumFactoryProxy也是FroumFactory的一种工厂实现,它的createForum具体实现如下:public Forum createForum(String name, String description)
23、0; throws UnauthorizedException, ForumAlreadyExistsException if (permissions.get(ForumPermissions.SYSTEM_ADMIN) Forum newForum = factory.createForum(name, descr
24、iption); return new ForumProxy(newForum, authorization, permissions); else throw n
25、ew UnauthorizedException(); 在这个方法中进行了权限验证,判断是否属于系统管理员。如果是,将直接从DbForumFactory对象factory的方法createForum中获得一个新的Forum对象,然后再返回Forum的子类代理对象ForumProxy。因为在Forum中也还有很多属性和操作方法,这些也需要进行权限验证。ForumProxy和ForumFactoryProxy起到类似的作用。Jive中有下列几个代理类:·
26、160; ForumFactoryProxy:客户端和DbForumFactory之间的代理。客户端访问DbForumFactory的任何方法都要先经过ForumFactoryProxy相应方法代理一次。以下意思相同。· ForumProxy:客户端和DbForum之间的代理,研究Forum对象的每个方法,必须先看ForumProxy对象的方法。· &
27、#160; ForumMessageProxy:客户端和DbForumMessage之间的代理。· ForumThreadProxy:客户端和DbForumThread之间的代理。User和Group也有相应的代理类。由以上分析看出,每个数据对象都有一个代理。如果系统中数据对象非常多,依据这种一对一的代理关系,会有很多代理类,将使系统变得不是非常干净,因此可以使用动态代理来代替这所有的代理类,具体实现将在以后章节讨论。2.5 批量分页查询与迭
28、代模式迭代(Iterator)模式是提供一种顺序访问某个集合各个元素的方法,确保不暴露该集合的内部表现。迭代模式应用于对大量数据的访问,Java Collection API中Iterator就是迭代模式的一种实现。在前面章节已经讨论过,用户查询大量数据,从数据库不应该直接返回ResultSet,应该是Collection。但是有一个问题,如果这个数据很大,需要分页面显示。如果一下子将所有页面要显示的数据都查询出来放在Collection,会影响性能。而使用迭代模式则不必将全部集合都展现出来,只有遍历到某个元素时才会查询数据库获得这个元素的数据。以论坛中显示帖子主题为例,在一个页面中不可能显示
29、所有主题,只有分页面显示,如图3-5所示。图3-5中一共分15页来显示所有论坛帖子,可以从显示Forum.jsp中发现下列语句可以完成上述结果:ResultFilter filter = new ResultFilter(); /设置结果过滤器 filter.setStartIndex(start); /设置开始点 filter.setNumResults(range);
30、; /设置范围 ForumThreadIterator threads = forum.threads(filter); /获得迭代器 while(threads.hasNext) /逐个显示threads中帖子主题,输出图3-5中的每一行 图3-5 分页显示所有帖子上述代码中主要是从Forum的threads方法获得迭代器ForumThrea
31、dIterator的实例,依据前面代理模式中分析、研究Forum对象的方法,首先是看ForumProxy中对应方法,然后再看DbForum中对应方法的具体实现。在ForumProxy中,threads方法如下:public ForumThreadIterator threads(ResultFilter resultFilter) ForumThreadIterator iterator = forum.threads(resultFilter); return new ForumTh
32、readIteratorProxy(iterator, authorization, permissions);首先是调用了DbForum中具体的threads方法,再追踪到DbForum中看看,它的threads方法代码如下:public ForumThreadIterator threads(ResultFilter resultFilter) /按resultFilter设置范围要求获得SQL查询语句 String query = getThreadListSQL(resultFilter, false); /获得result
33、Filter设置范围内的所有ThreadID集合 long threadBlock = getThreadBlock(query.toString(), resultFilter.getStartIndex(); /以下是计算查询区域的开始点和终点 int startIndex = resultFilter.getStartIndex(); int endIndex; / If number of results is set to inifinite, set endInd
34、ex to the total / number of threads in the forum. if (resultFilter.getNumResults() = ResultFilter.NULL_INT) endIndex = (int)getThreadCount(resultFilter); else endIndex = resultFilter.getNumResults() + startIndex;
35、60; return new ForumThreadBlockIterator(threadBlock, query.toString(), startIndex, endIndex, this.id, factory);ResultFilter是一个查询结果类,可以对论坛主题Thread和帖子内容Message进行过滤或排序,这样就可以根据用户要求定制特殊的查询范围。如查询某个用户去年在这
36、个论坛发表的所有帖子,那只要创建一个ResultFilter对象就可以代表这个查询要求。在上面threads方法代码中,第一步是先定制出相应的动态SQL查询语句,然后使用这个查询语句查询数据库,获得查询范围内所有的ForumThread的ID集合,然后在这个ID集合中获得当前页面的ID子集合,这是非常关键的一步。在这关键的一步中,有两个重要的方法getThreadListSQL和getThreadBlock:· GetThreadListSQL:获得SQL查询语句query的值
37、,这个方法Jive实现起来显得非常地琐碎。· GetThreadBlock:获得当前页面的ID子集合,那么如何确定ID子集合的开始位置呢?查看getThreadBlock方法代码,可以发现,它是使用最普遍的ResultSet next()方法来逐个跳跃到开始位置。上面代码的Threads方法中最后返回的是ForumThreadBlockIterator,它是抽象类ForumThreadIterator的子类,而ForumThreadIterator继承了Collection的I
38、terator,以此声明自己是一个迭代器,ForumMessageBlockIterator实现的具体方法如下:public boolean hasNext(); /判断是否有下一个元素public boolean hasPrevious() /判断是否有前一个元素public Object next() throws java.util.NoSuchElementException /获得下一个元素实例ForumThreadBlockIterator中的Block是“页”的意思,它的一个主要类变量threadBlock包
39、含的是一个页面中所有ForumThread的ID,next()方法实际是对threadBlock中ForumThread进行遍历,如果这个页面全部遍历完成,将再获取下一页(Block)数据。在ForumThreadBlockIterator重要方法getElement中实现了两个功能:· 如果当前遍历指针超过当前页面,将使用getThreadBlock获得下一个页面的ID子集合;·
40、160; 如果当前遍历指针在当前页面之内,根据ID获得完整的数据对象,实现输出;ForumThreadBlockIterator的getElement方法代码如下:private Object getElement(int index) if (index < 0) return null; / 检查所要获得的 element 是否在本查询范围内(当前页面内
41、) if (index < blockStart | index >= blockStart + DbForum.THREAD_BLOCK_SIZE) try /从缓冲中获得Forum实例 DbForum forum = factory.cacheManag
42、er.forumCache.get(forumID); /获得下一页的内容 this.threadBlock = forum.getThreadBlock(query, index); this.blockID = index / DbForum.THREAD_BLOCK_S
43、IZE; this.blockStart = blockID * DbForum.THREAD_BLOCK_SIZE; catch (ForumNotFoundException fnfe) return null;
44、; Object element = null; / 计算这个元素在当前查询范围内的相对位置 int relativeIndex = index % DbForum.THREAD_BLOCK_SIZE; / Make sure index isn't too large if
45、 (relativeIndex < threadBlock.length) try / 从缓冲中获得实际thread 对象 element = factory.cacheManager.threadCache.get(
46、 threadBlockrelativeIndex); catch (ForumThreadNotFoundException tnfe) return eleme
47、nt;ForumThreadBlockIterator是真正实现分页查询的核心功能,ForumThreadBlockIterator对象返回到客户端的过程中,遭遇ForumThreadIteratorProxy的截获,可以回头看看ForumProxy中的threads方法,它最终返回给调用客户端Forum.jsp的是ForumThreadIteratorProxy实例。ForumThreadIteratorProxy也是迭代器ForumThreadIterator的一个子类,它的一个具体方法中:public Object next() return new ForumThread
48、Proxy(ForumThread)iterator.next(), authorization, permissions);这一句是返回一个ForumThreadProxy实例,返回就是一个ForumThread实例的代理。这里,Jive使用代理模式实现访问控制实现得不是很巧妙,似乎有代理到处“飞”的感觉,这是可以对之进行改造的。从以上可以看出,Jive在输出如图3-5所示的多页查询结果时,采取了下列步骤:(1)先查询出符合查询条件的所有对象元素的ID集合,注意
49、不是所有对象元素,只是其ID的集合,这样节约了大量内存。(2)每个页面视为一个Block,每当进入下一页时,获得下一个页面的所有对象的ID集合。(3)输出当前页面的所有对象时,首先从缓冲中获取,如果缓冲中没有,再根据ID从数据库中获取完整的对象数据。上述实现方法完全基于即查即显,相比于一般批量查询做法:一次性获得所有数据,然后遍历数据结果集ResultSet,Jive这种批量查询方式是一种比较理想的选择。以上是ForumThread的批量显示,有关帖子内容ForumMessage也是采取类似做法。在每个ForumThread中可能有很多帖子内容(ForumMessage对象集合),也不能在一个
50、页面中全部显示,所以也是使用迭代模式来实现的。显示一个Forum主题下所有帖子内容的功能由ForumThread的messages()方法完成,检查它的代理类FroumThreadProxy如何具体完成:public Iterator messages(ResultFilter resultFilter) Iterator iterator = thread.messages(resultFilter); return new IteratorProxy(JiveGlobals.MESSAGE, iterator, authorization,
51、 permissions);实现的原理基本相同,返回的都是一个Iterator代理类,在这些代理类中都是进行用户权限检验的。Jive中也有关于一次性获得所有数据,然后遍历ResultSet的做法。这种做法主要适合一次性查询数据库的所有数据,例如查询当前所有论坛Forum,首先实现SQL语句:SELECT forumID FROM jiveForum获得所有Forum的forumID,这段代码位于DbForumFactory.java的forums方法中,如下: public Iterator forums() if (forums = null
52、) LongList forumList = new LongList(); Connection con = null; PreparedStatement pstmt = null; try con = ConnectionManager.getConnection(
53、); / GET_FORUMS值是SELECT forumID FROM jiveForum pstmt = con.prepareStatement(GET_FORUMS); ResultSet rs = pstmt.executeQuery(); while
54、(rs.next() forumList.add(rs.getLong(1); /将所有查询ID结果放入forumList中 catch (SQLExc
55、eption sqle) sqle.printStackTrace(); finally return new DatabaseObjectIterator(JiveGlobals.FORUM, forums, this); forums方法是返回一个DatabaseObject
56、Iterator,这个DatabaseObjectIterator也是一个迭代器,但是实现原理要比ForumThreadBlockIterator简单。它只提供了一个遍历指针,在所有ID结果集中遍历,然后也是通过ID获得完整的数据对象。总之,Jive中关于批量查询有两种实现方式:以ForumThreadBlockIterator为代表的实现方式适合在数据量巨大、需要多页查询时使用;而DatabaseObjectIterator则是推荐在一个页面中显示少量数据时使用。2.6 过滤器与装饰模式装饰(Decorator)模式是动态给一个对象添加一些额外的职责,或者说改变这个对象的一些行为
57、。这就类似于使用油漆为某个东西刷上油漆,在原来的对象表面增加了一层外衣。在装饰模式中,有两个主要角色:一个是被刷油漆的对象(decoratee);另外一个是给decoratee刷油漆的对象(decorator)。这两个对象都继承同一个接口。首先举一个简单例子来说明什么是装饰模式。先创建一个接口:public interface Work public void insert();这是一种打桩工作的抽象接口,动作insert表示插入,那么插入什么?下面这个实现表示方形木桩的插入:public class SquarePeg implements Workpublic void insert()S
58、ystem.out.println("方形桩插入"); 本来这样也许就可以满足打桩的工作需要,但是有可能土质很硬,在插入方形桩之前先要打一个洞,那么又将如何实现?可以编制一个Decorator类,同样继承Work接口,但是在实现insert方法时有些特别:public class Decorator implements Workprivate Work work;/额外增加的功能被打包在这个List中private ArrayList others = new ArrayList(); public Decorator(Work work)this.work=work;o
59、thers.add("打洞"); /准备好额外的功能public void insert()otherMethod();work.insert(); public void otherMethod()ListIterator listIterator = others.listIterator();while (listIterator.hasNext()System.out.println(String)(listIterator.next() + " 正在进行"); 在Decorator的方法insert中先执行otherMe
60、thod()方法,然后才实现SquarePeg的insert方法。油漆工Decorator给被油漆者SquarePeg添加了新的行为打洞。具体客户端调用如下:Work squarePeg new SquarePeg();Work decorator = new Decorator(squarePeg);decorator.insert();本例中只添加了一个新的行为(打洞),如果还有很多类似的行为,那么使用装饰模式的优点就体现出来了。因为可以通过另外一个角度(如组织新的油漆工实现子类)来对这些行为进行混合和匹配,这样就不必为每个行为创建一个类,从而减少了系统的复杂性。使用装饰模式可以避免在被油
61、漆对象decoratee中包装很多动态的,可能需要也可能不需要的功能,只要在系统真正运行时,通过油漆工decorator来检查那些需要加载的功能,实行动态加载。Jive论坛实现了信息过滤功能。例如可以将帖子内容中的HTML语句过滤掉;可以将帖子内容中Java代码以特别格式显示等。这些过滤功能有很多,在实际使用时不一定都需要,是由实际情况选择的。例如有的论坛就不需要将帖子内容的HTML语句过滤掉,选择哪些过滤功能是由论坛管理者具体动态决定的。而且新的过滤功能可能随时可以定制开发出来,如果试图强行建立一种接口包含所有过滤行为,那么到时有新过滤功能加入时,还需要改变接口代码,真是一种危险的行为。装饰
62、模式可以解决这种运行时需要动态增加功能的问题,且看看Jive是如何实现的。前面讨论过,在Jive中,有主要几个对象ForumFactory、Forum以及ForumThread和ForumMessage,它们之间的关系如图3-2所示。因此帖子内容ForumMessage对象的获得是从其上级FroumThread的方法getMessage中获取,但是在实际代码中,ForumThread的方法getMessage委托ForumFactory来获取ForumMessage对象。看看ForumThread的子类DbForumThread的getMessage代码:public ForumMessage
63、 getMessage(long messageID) throws ForumMessageNotFoundException return factory.getMessage(messageID, this.id, forumID);这是一种奇怪的委托,大概是因为需要考虑到过滤器功能有意为之吧。那就看看ForumFactory的具体实现子类DbForumFactory的getMessage功能,getMessage是将数据库中的ForumMess
64、age对象经由过滤器过滤一遍后输出(注:因为原来的Jive的getMessage代码考虑到可缓存或不可缓存的过滤,比较复杂,实际过滤功能都是可以缓存的,因此精简如下)。protected ForumMessage getMessage(long messageID, long threadID, long forumID) throws ForumMessageNotFoundException
65、0; DbForumMessage message = cacheManager.messageCache.get(messageID); / Do a security check to make sure the message comes from the thread. if (message.threadID != threadID) &
66、#160; throw new ForumMessageNotFoundException(); ForumMessage filterMessage = null; try / 应用全局过滤器
67、60; filterMessage = filterManager.applyFilters(message); Forum forum = getForum(forumID);
68、 /应用本论坛过滤器 filterMessage = forum.getFilterManager().applyFilters(filterMessage);
69、60; catch (Exception e) return filterMessage;上面代码实际是装饰模式的客户端调用代码,DbForumMessage 的实例message是被油漆者decoratee。通过filterManager 或forum.getFilterManager()的applyFilter方法,将message实行了所有的过滤功能。这就类似前面示例的下列语句:Work decorator = new Decorator(squarePeg);forum.getFilterManager()是从数据库中获取当前配置的所有过滤器类。每个Forum都有一套自己的过滤器类,这是通过下列语句实现的:FilterManager filterManager = new DbFilterManager();在DbFilterManager 的类变量ForumMessageFilter filters中保存着所有的过滤器,applyFilters方法实行过滤如下:public ForumMessag
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025还款协议合同范本
- 2025年度合同模板
- 2025年国际合作项目借款合同协议书
- 音乐情绪调控术
- 2025跨境电商合作合同模板
- 2025寒假合作活动合同模板
- 《心律失常护理要点》课件
- 《课件输出知识点》课件
- 2025年宿迁市泗洪县招聘国有企业及子公司招聘笔试参考题库附带答案详解
- 2025年包头市白云鄂博矿区文化旅游有限公司招聘笔试参考题库含答案解析
- 2024年3月ITSMS信息技术服务管理体系基础(真题卷)
- 节能评审和节能评估文件编制费用收费标准
- 2023-2024年《劳务劳动合同样本范本书电子版模板》
- 中国居民口腔健康状况第四次中国口腔健康流行病学调查报告
- MOOC 数据挖掘-国防科技大学 中国大学慕课答案
- 中药注射剂合理使用培训
- 第13课+清前中期的兴盛与危机【中职专用】《中国历史》(高教版2023基础模块)
- 2024年国家粮食和物资储备局直属事业单位招聘笔试参考题库附带答案详解
- 苏轼临江仙课件大学语文完美版
- 《施工测量》课件
- 情绪健康管理服务规范
评论
0/150
提交评论