📄 jive.html
字号:
<td WIDTH="100%" VALIGN="TOP">
<tr>
<td WIDTH="100%" CLASS="white"></td>
</tr>
<tr>
<td WIDTH="50%" bordercolor="#FFFFFF" CLASS="t1" bgcolor="#F0F0F0" align="center" nowrap>Jive 中的设计模式 </td>
<p> <td WIDTH="50%" bordercolor="#FFFFFF" CLASS="t1" bgcolor="#F0F0F0" align="center" nowrap>作者:SuperMMX </td></p>
</tr>
<tr> <td WIDTH="100%" bordercolor="#FFFFFF" CLASS="t" bgcolor="#F0F0F0" colspan="2">
<BR> <BR> <BR> <BR> 摘要: <BR> Jive 是一个开放源码的论坛项目, 也就是我们所常见的 BBS, 采用了 SUN <BR> 公司的 JSP 技术, 相比起 j2ee 这个庞大的体系结构, 其整个的设计思想非常 <BR> 精炼, 适用于中小型网站, 建立自己的论坛系统. 这篇文章我们就一起来看一看 <BR> Jive 中所应用的设计模式(Design Pattern). <BR> <BR> 正文: <BR> 关于设计模式, 这篇文章并不详细解释, 只是结合 Jive 来看看设计模式在一 <BR> 个实际项目中的应用及其整体的设计思想. 所以在读这篇文章前, 假设您对设计模 <BR> 式有一个感性的认识, 对其具体应用以及实现方法有些疑问, 并渴望了解其思想, <BR> 并使用过 Jive. 本文将一同来探讨这个问题. 为什么选择 Jive 而不是选择一个新的 <BR> 例子重新开始呢? 有以下两个原因: 1, 我们很多人对 bbs 这样一个事物比较熟悉, <BR> 很清楚 bbs 所具有的一些基本功能, 如果自己作为设计者来设计这样一个 web bbs, <BR> 会怎么想, 再看看别人是怎么实现的, 有对比才能明白自己设计上的缺点, 看到别人 <BR> 的优点才能更快地进步. 2, Jive 并不是非常地复杂, 并且包括了一个完整的实现方 <BR> 案, 从底层到高层, 从后端到前端, 都有很好的文档, 这些都能更好地帮助我们理解 <BR> 它. <BR> 这里我们所用的 Jive 的版本采用其开发者作为正式发布的 1.0 版, 其最新版 <BR> 为 1.21, 对其结构作了少量改动, 主要增加了 jsp tag 的支持, 这种技术不属于我 <BR> 们的讨论范围, 以后有机会可以共同学习. <BR> Jive 中所使用的设计模式, 对设计模式的三种类型 -- 创建型, 结构型, <BR> 行为型 -- 都有涉及, 这样也能比较全面地了解设计模式. 我们先来自己设计一下, <BR> 运用面向对象的思想, 可以很容易知道, 整个系统主要需要这几个对象: <BR> <BR> 1, Forum -- 一个讨论区, 也就是一个版面. <BR> 2, Thread -- 一条线索, 也就是有关同一个主题的所有的回文. <BR> 3, Message -- 一条消息, 也就是一个用户发的一篇贴子. <BR> (以后我们就用"贴子"这个叫法) <BR> 4, User -- 一个用户, 也就是讨论区的使用者. <BR> <BR> 好了, 我们需要的东西都在了, 它们之间的关系十分复杂, 怎么把它们组织地 <BR> 很符合我们的思路又能容易扩充呢? 我想大家都有自己的想法了, "我能这么这么做", <BR> "我可以这样这样设计", 我们一起来看看 Jive 是怎么做的. 下面是其整体结构: <BR> <BR> |~~~~~~~~~~~~~~~~~~| <BR> | Skin 设计者 | <BR> |__________________| <BR> | | <BR> | | 使用 <BR> \ / <BR> |~~~~~~~~~~~~~~~~~| <BR> | 各种对象的接口 | <BR> |_________________| <BR> | | <BR> | | 被实现 <BR> \ / <BR> |~~~~~~~~~~~~| <BR> | 权限控制 | <BR> |____________| <BR> | | <BR> | | 控制 <BR> \ / <BR> |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| <BR> | 对数据库进行操作的各种对象 | <BR> |_____________________________| <BR> | | <BR> | | 取连接 <BR> \ / <BR> |~~~~~~~~~~~~~~~~| <BR> | 数据库连接池 | <BR> |________________| <BR> <BR> (图 1) <BR> <BR> 下面是其类的大概的继承情况: <BR> <BR> |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| <BR> | Interface A | <BR> |___________________________________| <BR> | | <BR> | implements | <BR> | | <BR> |~~~~~~~~~~~~~~~~~| | <BR> | Proxy A | | <BR> |_________________| | <BR> | <BR> | <BR> |~~~~~~~~~~~~~~~~~~| <BR> | Database A | <BR> |__________________| <BR> (图 2) <BR> <BR> <BR> 好了看到这里, 如果您对设计模式有了解的话, 从上面所写的伪名字中, 可以 <BR> 看到一些熟悉的东西. 请让我做一些解释. 上面的图表示的是类的继承关系, A 代 <BR> 表上面所提到的四种对象, Interface A 表示名为 A 的一个接口, 相信大家对接口 <BR> 都不陌生, 接口在 java 中有着重要的作用. Proxy A 表示一个名为 ProxyA 的类, <BR> 实现 A 接口. Database A 表示名为 DbA 的一个类, 实现 A 接口. 但设计模式并 <BR> 没有从中体现出来,设计模式所要表现的是怎么样更好地组织对象之间的逻辑关系, <BR> 怎么样才能更好地扩充现有的东西而不需要作很大的改动, 而不仅仅是类的继承. <BR> 还有一点需要说明的是, 设计模式总的原则是针对接口编程, 而不关心其具体 <BR> 实现, 这样搭起来的是一个架子, 还需要作许多具体的编程才能真正的完成系统. <BR> <BR> 下面, 我们就分别从设计模式的三种类型来看 Jive 使用了其中的哪些. <BR> <BR> <BR> 一, 创建型模式 (Creational Patterns) <BR> <BR> 这一类型的设计模式, 所要表现的是对象的创建过程及和用户所使用的对象之间 <BR> 的关系. <BR> <BR> 1, Jive 中在 Forum 之上又加了一层, ForumFactory, 来实现对 Forum 的一些控 <BR> 制, 比如创建新的讨论区, 删除一个讨论区等等. 这个类实际上是整个系统的入口, <BR> jsp 中所做的一切都要从得到这个类的一个实例开始. 它的一些子类和它的关系如 <BR> 下: <BR> |~~~~~~~~~~~~~~~~~| <BR> | ForumFactory | abstract <BR> |_________________| <BR> | | <BR> | extends | <BR> | | <BR> |~~~~~~~~~~~~~~~~~~~~| |~~~~~~~~~~~~~~~~~| <BR> | ForumFactoryProxy | | DbForumFactory | <BR> |____________________| |_________________| <BR> <BR> (图 3) <BR> <BR> 我们来看一下得到一个 ForumFactory 实例的过程: <BR> FactoryForum factory = ForumFactory.getInstance(aAuthorization); <BR> 就得到了 ForumFactory 的实例, 这个最终用户(skin 设计人员)所使用的是它的子 <BR> 类 ForumFactoryProxy 的实例, (其中涉及到另一个模式, 后面将会提到), 但实际 <BR> 上真正在做实际工作的是 DbForumFactory 或者是一个指定的类的实例, 相关代码如 <BR> 下: <BR> <BR> From ForumFactory.java <BR> <BR> private static String className = "com.coolservlets.forum.database.DbForumFaactory"; <BR> // 系统缺省的 ForumFactory 的一个具体的子类. <BR> <BR> private static ForumFactory factory = null; <BR> <BR> ForumFactory.getInstance() <BR> <BR> String classNameProp = PropertyManager.getProperty("ForumFactory.className") <BR> // 可以通过配制文件来选择其他的具体的子类. <BR> <BR> if (classNameProp != null) { <BR> className = classNameProp; <BR> } <BR> try { <BR> //Load the class and create an instance. <BR> Class c = Class.forName(className); <BR> factory = (ForumFactory)c.newInstance(); <BR> } <BR> catch (Exception e) { <BR> System.err.println("Failed to load ForumFactory class " <BR> + className + ". Jive cannot function normally."); <BR> e.printStackTrace(); <BR> return null; <BR> } <BR> <BR> 它使用的是 Abstract Factory (抽象工厂)设计模式. 给用户一个使用一系列相关对象 <BR> 的接口, 而不需要指定其具体的类. 也就是说, skin 设计人员写的 jsp 中不应该出现 <BR> new DbForumFactory 之类的语句. Jive 中 AuthorizationFactory 也使用了这个设计模式 <BR> <BR> 2, Jive 中有一个很不错的想法, 就是对贴子的内容和标题可以进行过滤, 比如过滤 html <BR> 过滤一些脏话, 对附加的代码进行高亮显示, 转换链接等等. 如果我要实现这样的功能, 有有?<BR> 下几种方法: (1) 在 Message.getBody() getSubject() 中进行控制, (2) 在 Thread 中得得?<BR> Message 后进行转换. 还需要考虑的问题是这些过滤的操作必须能够很方便地添加删除. 不不?<BR> 的目标所用的设计方法是不一样的, Jive 是这样做的: 以版面为主, 把这些过滤器看作是鞍婷?<BR> 的属性, 过滤器只对其所属的版面有效, 所以 Jive 中使用了 (2), 这并不是主要的, 重要要?<BR> 是这些过滤器该怎么来组织. 我们先来看看需求: 能动态添加删除, 功能类似, 贴子的显示示?<BR> 其具体怎么创建, 如何表现无关. 似乎目标只有一个 -- Prototype(原型) 设计模式. 看看 <BR> Jive 的具体实现. <BR> <BR> |~~~~~~~~~~~~~~~~~~~~| <BR> | ForumMessage | <BR> |____________________| <BR> | <BR> | implements <BR> | <BR> |~~~~~~~~~~~~~~~~| Prototype |~~~~~~~~~~~~~~~~~~~~~| <BR> | ForumThread |-----------> | ForumMessageFilter | <BR> |----------------| |---------------------| <BR> | getMessage() o | | clone() | <BR> |______________|_| |_____________________| <BR> | / | <BR> |~~~~~~~~~~~~~~~~| |~~~~~~~~~~~~~~~| |~~~~~~~~~~~~~| <BR> | aFilter.clone()| | HighlightCode | | HTML | <BR> |________________| |---------------| |-------------| ...... <BR> | clone() o | | clone() o | <BR> |___________|___| |___________|_| <BR> | | <BR> |~~~~~~~~~~~~~~~| |~~~~~~~~~~~~~~~| <BR> | 返回一个实例 | | 返回一个实例 | <BR> |_______________| |_______________| <BR> <BR> (图 4) <BR> <BR> 上图作了少许的简化. Jive 用的时候是把这些过滤器存在数据库中, 可以动态设置 <BR> 属性, 比较方便. 来看一些代码: <BR> <BR> From: DbForumThread.java <BR> <BR> public ForumMessage getMessage(int messageID) <BR> throws ForumMessageNotFoundException <BR> { <BR> ForumMessage message = factory.getMessage(messageID); <BR> <BR> //Apply filters to message. <BR> <BR> message = forum.applyFilters(message); <BR> <BR> //通过 Forum 来实现, 因为 Filter 是 Forum 的属性, <BR> //Thread 只能通过 Forum 的接口来访问. <BR> <BR> return message; <BR> } <BR> <BR> From: DbForum.java <BR> <BR> public ForumMessage applyFilters(ForumMessage message) { <BR> <BR> for (int i=0; i < filters.length; i++) { <BR> message = filters[i].clone(message); <BR> } <BR> <BR> //可能会有多个过滤器, 依次来操作. <BR> <BR> return message; <BR> } <BR> <BR> <BR> <BR> 二, 结构型模式 (Structural Patterns) <BR> <BR> 这一类的模式关心类和对象之间怎么组织起来形成大的结构. 主要使用继承来 <BR> 组织接口或实现. <BR> <BR> 1, 我们再接着思考一下, 用户之间应该有所区别, 有 Guest 用户, 可以让他来看一 <BR> 看, 但不能发贴子, 正式用户可以发贴子, 查看自己的个人信息, 版面管理者(称之为 <BR> 版主)应该可以控制贴子, 比如加上适当的标记, 收入精华区, 甚至删除贴子等等, 而 <BR> 系统管理者应该具有更高的权限, 比如开新的版面, 删除用户等操作. 怎么实现这个 <BR> 功能呢? 我们知道, Jive 中所有实际的操作都是由 database 目录下的类所实现的, <BR> 如果把权限控制加到数据库这一层的话, 这一层不但臃肿, 而且写好以后, 如果要改 <BR> 的话, 需要修改的地方很多, 还容易出错, 所以可以在这一层之上再加一层, 单独进 <BR> 行权限控制. 这样就把 "该不该做" 和 "怎么做" 分割开来, 利于以后修改. 其实这 <BR> 也是面象对象的一个思想 -- 一个对象不要负担太多的责任. 这种方法在设计模式中 <BR> 称为 Proxy (代理) 模式. 好比生产厂家和代理商的关系. (当然, 在 Jive 中这个比 <BR> 喻不太合适). Proxy 的目的就是给另一个对象提供一个代理来控制对它的访问. <BR> Proxy 模式一直贯穿 Jive 的始终, 几乎所涉及到的对象都需要. 其结构如图 2 <BR> 所示. <BR> <BR> 从前面已经知道, ForumFactory 是整个系统的开始. 再来看看 ForumFactory <BR> 的代码: <BR> <BR> From ForumFactory.java <BR> <BR> ForumFactory.getInstance() 的最后: <BR> <BR> ForumFactoryProxy proxy = new ForumFactoryProxy( <BR> factory, <BR> authorization, <BR> factory.getPermissions(authorization) <BR> ); <BR> return proxy; <BR> <BR> 前面得到的 factory 是 DbForumFactory 的实例, 这里把这个实例又用 <BR> ForumFactoryProxy 封装起来. 最后返回一个 ForumFactoryProxy 的实例. 也就是 <BR> 说 jsp skin 的设计者所用的 ForumFactory 实际上是 ForumFactoryProxy. 接着看 <BR> 看 ForumFactoryProxy 里发生了什么事, 那一个小片段做例子: <BR> <BR> 其构造函数中的 Factory 就是一个 DbForumFactory 的实例, 由它来做具体的 <BR> 工作. Authorization 可以认为是一个认证过的当前用户(指实际的浏览器的使用者), <BR> ForumPermissions 可以认为是当前用户的权限. <BR> <BR> public Forum createForum(String name, String description) <BR> throws UnauthorizedException <BR> { <BR> //这里就对权限进行了检查, 具有系统管理员权限, 则可以进行相应的操作, <BR> //否则抛出异常. <BR> <BR> if (permissions.get(ForumPermissions.SYSTEM_ADMIN)) { <BR> Forum newForum = factory.createForum(name, description); <BR> return new ForumProxy(newForum, authorization, permissions); <BR> } <BR> else { <BR> throw new UnauthorizedException(); <BR> } <BR> } <BR> <BR> public Forum getForum(int ID) throws ForumNotFoundException, <BR> UnauthorizedException <BR> { <BR> Forum forum = factory.getForum(ID); <BR> ForumPermissions forumPermissions = forum.getPermissions(authorization); <BR> //Create a new permissions object with the combination of the <BR> //permissions of this object and tempPermissions. <BR> ForumPermissions newPermissions = <BR> new ForumPermissions(permissions, forumPermissions); <BR> //Check and see if the user has READ permissions. If not, throw an <BR> //an UnauthorizedException. <BR> if (!( <BR> newPermissions.get(ForumPermissions.READ) || <BR> newPermissions.get(ForumPermissions.FORUM_ADMIN) || <BR> newPermissions.get(ForumPermissions.SYSTEM_ADMIN) <BR> )) <BR> { <BR> throw new UnauthorizedException(); <BR> } <BR> <BR> // 同上所述. <BR> // 这里得到的 forum, 是一个 DbForum 的实例, 跟 ForumFactory 一样, <BR> // 返回一个封装过的代理对象, 来对 forum 进行权限控制. <BR> <BR> return new ForumProxy(forum, authorization, newPermissions); <BR> } <BR> <BR> 其他所有的对象都是类似的. 这里就不再赘述. <BR> <BR> <BR> 三, 行为型模式 (Behavioral Patterns) <BR> <BR> 这一类的模式关心的是算法以及对象之间的任务分配. 它所描述的不仅仅是对象或类 <BR> 的设计模式, 还有它们之间的通讯模式. <BR> <BR> 1, 下来看看怎么从一个 Forum 中得到一些 Thread. 当然这里要涉及到数据库, 我们 <BR> 先设计一个最简单的数据库表, 表名: thread, 字段 ThreadID int, ForumID int, 其 <BR> 他内容我们不关心. 然后比如 Forum 中的一个方法, getThreads() 来返回当前 Forum <BR> 所有的 Thread. 然后就可以这样做: <BR> <BR> public ForumThread[] getThreads() <BR> { <BR> 1, 从数据库里面查询, 取出所有的 ThreadID, <BR> 2, 根据 ThreadID 构造 ForumThread 对象, <BR> 3, 返回一个数组. <BR> } <BR> <BR> 这样做最省事, 最简单了, 但好不好呢? 还得看需求, 比如我要求根据时间排序, <BR> 就还得修改这个方法, 也就是说需要修改 DbForum 对象. 那为什么不把取 Thread 这个 <BR> 操作单独拿出来呢? 这样的好处就是功能独立化, 使 DbForum 更简单, 符合前面我们所 <BR> 提到的不要让对象负担太多的责任这个原则. 也许你会说, 如果要修改的话, 不是都得 <BR> 修改吗? 放哪里是一样的, 这样没错, 但只限于很小的系统, 如果系统一大, 那么就可 <BR> 能做 DbForum 中的简单查询和一些比较复杂的查询的程序员就不是一个人, 这样牵扯到 <BR> 需要改动的地方较多, 但分离以后, 只需要一个人改很少的地方就可以完成. 回过头来 <BR> 再看看问题, 这里要返回一群 ForumThread 对象, 而且它们之间还可能有一定的先后关 <BR> 系, 怎么来做这个工作呢? Iterator 设计模式是一个合适的选择. Iterator 模式提供 <BR> 了一个连续访问一大群对象的方法, 而不需要知道它们的表现形式, 比如按什么方式排 <BR> 序等等. <BR> 好了, 来看看 Jive 的具体实现. 由于 Java 本身已经有这样的接口, Iterator 接 <BR> 口, 所以只要实现这个接口就可以了. <BR> <BR> From DbForum: <BR> <BR> public Iterator threads() { <BR> return new DbForumIterator(this, factory); <BR> } <BR> <BR> <BR> From DbForumIterator: (做了改动) <BR> <BR> public class DbForumIterator implements Iterator { <BR> <BR> public DbForumIterator(...) <BR> { <BR> ... <BR> } <BR> <BR> public boolean hasNext() //是否还有元素 <BR> { <BR> ... <BR> } <BR> <BR> public Object next() // 得到下一个元素 <BR> { <BR> ... <BR> } <BR> <BR> ... <BR> <BR> } <BR> <BR> 那么 jsp 中可以这样访问: <BR> <BR> Iterator threads = aForum.threads(); <BR> while (threads.hasNext()) <BR> { <BR> ForumThread thread = (ForumThread)threads.next(); <BR> 做一些操作. <BR> } <BR> <BR> 从中可以看出, 通过使用 Iterator 把 Threads 的一些具体细节进行了封 <BR> 装, 提供统一的接口. Jive 中这个设计模式也是用的非常多, 多个用户显示, <BR> 多个版面显示, 多个线索, 多个贴子都需要由它来实现. <BR> <BR> <BR> 小结: <BR> <BR> 上面我们一起探讨了一下设计模式在 Jive 中的应用情况, 当然只是很简单, 很 <BR> 肤浅, 也很片面, 不过总算能对设计模式有些认识. 实际上, 设计模式就是吸收许多前 <BR> 人的经验, 把设计中一些重要的和重复出现的一些模式总结起来, 给出一个系统的命名, <BR> 给出相应的解释和评价, 这个工作最先由 4 位软件大师所做, 他们合写了一本书 -- <BR> Design Pattern: Elements of Reusable Object-Oriented Software, 后来, 人们把 <BR> 他们称为 GoF (Gang Of Four). <BR> 对于设计模式, 可能在我们的实际项目中自觉不自觉地在使用着, 比如 Factory <BR> Method 模式, Abstract 模式, Singleton 模式, Iterator 模式, 等等, 只是概念不是非?<BR> 的明确, 设计可能还有不太合理的地方, 处于一种跟着感觉走的状态, 相信很多有经验 <BR> 的设计者, 原来没有接触设计模式, 一旦接触以后, 会有一种恍然大悟的想法, 哈, 原 <BR> 来是这么回事. 学习设计模式, 能很好地帮助我们设计, 在相同的问题, 相同的背景下, <BR> 可以直接使用它, 有的时候不知道该选择哪种好, 就需对问题进行更深一层的分析, 进行 <BR> 综合权衡, 对设计模式也要进行更深刻的理解, 才能得到好的结果, 这也是一个进步的 <BR> 过程. <BR> 对于笔者来说, 刚刚接触设计模式, 有了一点粗浅的理解, 就冒昧写了这篇算是一 <BR> 点心得的东西, 也是对自己的挑战, 中间犯的一些错误, 还请指正, 谢谢. <BR>
<!-- 设计模式 -->
</td>
</tr>
</td>
</tr>
</div>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -