请教这个应该当成值对象属性吗?

08-05-19 freebox
模型:分类、书籍。

class Category{
    Category parent;
    List<Category> children;
    CategoryState state;
}
class Book{
    Category category;
}
class CategoryState{
    int bookCount=0;
}
<p class="indent">

问题:bookCount应该如何设计。
说明:
现在有需求查询各级分类中书籍的数量bookCount。
由于分类下不断增加子分类,现在想查询最顶层的分类中的书籍数量,需要遍历顶级分类的所有子分类并递归,最后求和,效率比较低下。
查询和增加Book都比较频繁。
请教这种情况应该如何设计,是否应该把bookCount设计在Category中并在增加Book时更新分类及所有父级分类?或有更好的方法查询这种分类树。

killer
2008-05-22 19:17
>>>是否应该把bookCount设计在Category中并在增加Book时更新分类及所有父级分类?

个人感觉在新增和查询比较频繁的情况下可以这么做,对于增加Book时更新分类及所有父级分类,可以放在事件里面在,让它自动触发执行

freebox
2008-05-22 22:28
你的意思是建触发器在DB级别处理?或是由对象关联不断检索它的直接、间接根对象一层层更新?
这两种效率都不太高。
目前采取为Category建立间接子结点树和间接父结点树的方式处理,需要维护一个ManyToMany关系,查询用了in查询,暂时先看看,因为对Category的更新并不多,建立Category之后就基本稳定了。

banq
2008-05-26 11:08
>查询最顶层的分类中的书籍数量,需要遍历顶级分类的所有子分类并递归,最后求和
这是典型的composite模式使用场景,建议使用composite模式进行求和,将分类树形的遍历封装起来。

至于是否当成值对象,我觉得没有必要这样教条,只要使用模式来参与实现,具有一定解耦性就是适当设计了,DDD也说没有设计准则和定理,所以,你也不能拿DDD本身概念往上靠。这些都是范了形式主义倾向。

freebox
2008-05-26 12:27
非常感谢banq先生对我的问题的关注。
最初的设计就是这么做的,因为Category本身持有的父子都是它自己或自己的集合,实现也容易。给了一个专用的查询树和其子树的Book数量的查询器,但是他们说查询一层中的一个父结点就需要发出10多条SQL,认为不合理,树太高,而Book随时增加,缓存似乎用处也不大。
目前试验使用间接子树结点统计,每个父结点都拥有它的所有子结点的标识集合,统计一层的一个父结点的bookCount只需要一个in查询。

killer
2008-05-28 20:32
>>>你的意思是建触发器在DB级别处理?或是由对象关联不断检索它的直接、间接根对象一层层更新?

不是在DB级别处理,是你在BookService里面调用DAO或Repository里持久化完Book后触发Category的方法,完成状态的更新。
class Category{
Category parent;
List<Category> children;
CategoryState state;
public incBookCount(){
state.incCount();
parent.incBookCount();
}
}

class CategoryState{
int bookCount=0;
public incCount(){
bookCount++;
}
}

freebox
2008-05-28 22:51
感谢killer指点。
或许在Category移动时要重新统计,但是前期调查认为这种操作较少。
其实我也很矛盾,我是信任内存的,这个问题和:
http://www.jdon.com/jivejdon/thread/34080.html
有些类似,目前已经按照结点集合操作了,但还是按您的方案准备了一套备用Repository实现,非常感谢。