最近在做CSDN新论坛的设计,我就走了OO设计上的死牛角了。一度头大的不知所以然。下面来看我所走的弯路,希望对大家有所帮助。
先说功能需求
我们有这样的需求:
论坛由很多具体论坛组成。对于某个具体论坛来说,它是下述功能的组合,可能是其中一个功能的组合,也可能是其中几个功能的组合,不过确定组合后,有哪些组合就很少会发生变化,这些功能包括:
积分制、勋章制、贴图、帖链接、可以发投票帖 等等......
每个具体论坛,上述功能组合都可以不同。
简单来看我走的死牛角:
以论坛帖子类的设计为例。
不论用上述那些功能组合,一个帖子类,当然会有一个基类,这个基类包含最最基本的帖子信息,比如帖子编号、标题、发帖者等等。
对于 A 论坛,它选择了使用积分制功能,则A 论坛的帖子类应该还包括一个帖子分数的字段来记录跟积分制有关的信息。
对于B论坛,它选择了使用贴图功能,则B论坛的帖子类应该还包含一个字段,来记录相关的图片链接。
对于C论坛,它选择了同时使用积分制和贴图功能,则C论坛的帖子类应该还包含上述两个字段。
………………….
我们会有很多种组合。非常非常多。
如果我们用每个论坛实现一个派生自基类帖子类的子类,问题会是:组合太多了。而且以后丰富功能的时候,每新增一个功能,需要新增的子类会不可想象。
如果使用一个超级类,把所有功能都封装到一个类来。每个功能涉及的属性都有默认值。
则会给这个类的使用者带来很多意想不到的问题:
因为这个类相关的内部逻辑可能是开发人员A设计的。而使用者会是开发人员B。
某种情况可能会需要对这个超级类的1、2、3三个属性给值。另外一种情况则….. 之前有多少种组合,这里可能就有多少种情况。
让开发人员B熟悉这么多种组合,很容易啥时候就出问题。复杂,太复杂了。
……………………………………
上面就是我陷入的死牛角。
解决方法:
一、如果OO设计上出现困惑,先不要考虑OO的设计,先考虑数据库的设计,看你数据表是如何设计的。你完全可以把数据表的结构映射到OO的设计上来。
二、如果OO设计上出现困惑,先不要考虑OO的设计,先考虑界面的设计,然后从界面的功能转到OO的设计上来。
这里不是说OO不好,而是由于还没有对这方面的抽象习惯过来,通过对整个流程的思考,会帮助你构造好的OO类。
就象模式一样,也是别人经过很多实践得出来的,一般都叫做refactor to patterns,即对自己的编码反复重构,最后这些编码就成了模式,或与模式相似。
不要硬套OO或者模式设计。
对于我这里的设计,
数据库上存储帖子信息,显然是可不管你每个论坛使用了哪些功能,而是认为所有功能你都使用了,对于没使用的功能,则认为对应的字段使用的是默认值。
不论用那种组合论坛,因为他们界面展示上完全不一样,每一套功能组合,我们都需要提供一套页面模版和接受读取参数功能来处理。这样其实组合方式并不是多得不可接受,仍然是可接受的。
想明白上述两点,设计就很简单的,就不会过度设计,钻OO设计的牛角了。
打印 | 张贴于 2006-03-13 11:33:00 | Tag:.net 编程心得 技术随笔 网站开发管理相关内容
留言反馈
Jolt Winner: Prefactoring by Ken Pugh (O'Reilly)
Productivity Winners:
* Innovation Happens Elsewhere: Open Source as Business Strategy by Ron Goldman, Richard P. Gabriel (Morgan Kaufmann)
* Producing Open Source Software: How to Run a...
借鉴windows shell扩展,一种文件类型对应一个扩展,也有通用的扩展,windows用注册表保存插件信息
"数据库上存储帖子信息,显然是可不管你每个论坛使用了哪些功能,而是认为所有功能你都使用了,对于没使用的功能,则认为对应的字段使用的是默认值。"
我觉着这样设计数据库好像不合理,难道我新增一项功能,就的添加一个字段,我想采用一个字段,这个字段存储xml,然后根据xml实例化插件
新社区复杂的一个地方,就是可以按照你说的方式展示,同时旧有BBS的方式仍然可以展示。
至于复杂性。没办法,
1是必须考虑性能问题。
2是必须考虑灵活的功能
bbs毕竟不是文档中心,bbs重在参与过程,发言的多,总结的少。
1. 一个topic只能发到一个分类里面,实际上有是涉及到多个分类的。比如jdbc的问题可能属于j2ee/mysql
2. 分类组织过于笼统。分类应该细致的象搜索引擎一样,没有的分类可以马上建立。利用ajax可以很容易实现
3. 一个topic可以是投票,blog,提问。。。有树形reply分支。
实现以上3点,信息检索就相当方便,也更有价值。
对我也有同样感觉。
但是,做用例的话,之前也这么做过。最后又花时间,进度有慢。
而且更关键的是,功能变化太快。比如目前推荐WEB2.0的思想,那很多功能就发生变化了。
给自己网站做东西。可没法用合同定义好,只实现那些功能。
头大呀。而且进度卡的狠紧。
这个方法不错,甚至可以做一个客户端插件配置程序,一个客户端选择插件后,动态生成需要的数据结构。
反正插件选择后,改动不会很大。
我觉得应当是一个子论坛一张表,但是所有子论坛有公共属性
我的回复:
CSDN 目前有300多个大小论坛。
新社区会同时开通用户组论坛和帖吧功能。
新的CSDN的论坛上十万很正常。
装饰模式会使一个系统带有“大量的小对象”,对于维护代码的程序员来说,他们看起来都差不多,维护起来很头疼。
另外,
每个论坛的可组合模式很多,多的不计其数。
前面说的“不论用那种组合论坛,因为他们界面展示上完全不一样,每一套功能组合,我们都需要提供一套页面模版和接受读取参数功能来处理。这样其实组合方式并不是多得不可接受,仍然是可接受的。”
并没有说对。
正确的应该是组合是多的不计其数。但是具体到某个功能,比如发帖页面。
可能几十种组合用的发帖模版都是一个模版。
可能会出现下面的情况:
A 论坛是 aa\bb\cc\dd 功能的组合。它的发帖页面用的是1号发帖模版,列表页面是用的 3号列表模版。
B 论坛是 ww\dd\ee\rr 功能的组合。它的发帖页面用的是1号发帖模版,列表页面是用的 3号列表模版。
C 论坛是 oo\ww\e\r\d 功能的组合。它的发帖页面用的是1号发帖模版,列表页面是用的 1号列表模版。
..................
组合会非常多。但是具体到某个功能,则这个功能的模版是有限个数的。
可能最后会有10套发帖模版、10套列表模版。 但是组合模版可能就有1000种。
OO设计的一个重要原则是:能够使用组合就尽量不用继承。根据这个原则来看应该优先考虑是不是有利用组合原则的解决方案,比如说前面一个朋友提到的装饰模式(Decorator)可能就比较合适。
第二个问题是,是不是说一个类就该对应一张表呢?就像作者说的,二十个类就有二十张表?我觉得不一定,从关系模型到对象默想必然会有一个映射,是否能够或者说应该以一对应都是要具体问题具体分析的。
不知道我的观点是不是正确,很高兴和大家讨论。
yujianqiu@gmail.com
我不赞成你提的说法。
ForumBase------------------->ForumMetadata
| * + UseImage
| | + UseGrade
| | + UseLink
| | + other capabilities....
| |
| +------------------------>IForumPlugins
| |
| +----------> ImagePlugin
Forum(没有任何功能) +----------> GradePlugin
我觉得应当是一个子论坛一张表,但是所有子论坛有公共属性
功能的组合可能会很多,但是,子论坛并不多啊,
只要创建论坛时通过一个配置创建就可以了,我还是支持OO方式
把论坛的定义当作元数据,写代码时只按照元数据去操作论坛就可以了
结构如下,请参考
ForumBase------------------->ForumMetadata
| * + UseImage
| | + UseGrade
| | + UseLink
| | + other capabilities....
| |
| +------------------------>IForumPlugins
| |
| +--------------> ImagePlugin
Forum(没有任何功能) +--------------> GradePlugin
对于论坛的帖子,一些基本的属性可以定义为共同的基类。然后我们可以为每一种方式的帖子,建立新的类,这个类应该是细粒度的,便于利用装饰模式进行组合。例如为积分建立一个专门的子类,为贴图建立一个专门的子类,利用装饰模式可以非常方便的建立各自的组合类。即使未来有扩展,这种装饰的方式仍然是可行的。
这样的过程已经有了方法论的总结:RUP。RUP强调用例驱动建模,而用例。也就是用户需求的UML描述,在你的案子里可以理解为你说的“先考虑界面的设计,然后从界面的功能转到OO的设计上来”。
比如可以回复就可以认为是一个插件。
帖子高亮显示又是一个插件。
积分制也是一个插件。
贴图也是一个插件。
每个插件涉及到一个表的话。
20个插件,就要增加20个表。
那再多呢???
我考虑的优先级,
第一是性能,
第二才是丰富的功能。
照这样子来看的话,如果你以后要增加新的功能怎么办?为什么不做成插件机制?