王朝网络
分享
 
 
 

反思以前对“多对多”关系处理的设计

王朝other·作者佚名  2006-05-27
宽屏版  字体: |||超大  

反思以前对“多对多”关系处理的设计

很多公司的笔试题都喜欢考这一道:有n个供货商和m种货品,每个供货商可能供应多种货品,每种货品也有可能由多个供货商供应,建立相应的数据库表维护供应商和货品以及他们的供货关系。

这类多对多问题其实在真实的系统中很常见,比如用户--角色,角色--权限,用户--用户组等等。对接触过类似的系统的人这当然不是问题,三个表,套路来的嘛。

当然有其他方式,比如供货商表中添一个货品列表字段,用xml或者约定的格式保存货品列表,但是这样一是查询更新效率很低(查询的时候要解析数据,更新的时候要解析并重新组合数据,反向查找的时候更低效),二是没有办法建立外键约束。对第反向查找的问题,如果我们允许数据冗余并且有信心维护好数据一置性的话可以同时在货品表中添加一个供货商列表字段。但是除了效率、约束(以及冗余,假如它也算问题的话)之外,还有个最重要的问题我们忽略了:这样的设计不优雅。

但是在数据库表之外,我们做系统的时候是怎么处理类对应关系的呢?我没有看到过别人的设计,但是在我的系统中使用的其实是类似于上面说的第二种方式,比如在用户对象中有一个角色列表字段,存储了与用户关联的角色。当然解析数据带来的效率问题不存在了,因为角色信息是以原始方式保存的;数据一置性问题也由数据库解决。系统工作的很稳定也很快,但是我们一直忽略了这个问题:这样的设计优雅吗?我认为我们可以做的更好。

假如我们象设计数据库表一样的设计系统,系统本来可以做成这样子的:

(Database)

tb_user tb_user_role tb_role

------------------------------------------------------------------------------------

UserDAO UserRoleDAO RoleDAO

UserMng UserRoleMng RoleMng

这样user的model对象里面就不需要维护role列表了。我们需要访问关联关系的时候可以通过UserRoleMng来获得列表,如果我们需要访问role对应的user列表也一样的简单(在原来的设计中要遍历全部user)。

更进一步,我们把对这种多对多关联关系的处理抽取出来,做一个基类:

abstract class AbstractRelationManager{

protected void init();

protected void addRelation(id1,id2){

...

}

protected void deleteRelation(id1,id2)

...

}

protected List getId1ListById2(id2){

...

}

protected List getId2ListById1(id1){

...

}

}

然后UserRoleMng、RolePermissionMng或者其他类似的关系管理器都可以继承自AbstractRelationManager并由超类处理关联查询的逻辑:

class UserRoleMng{

public void addRelation(userId,roleId){

super.addRelation(userId,roleId);

}

...

}

如果高兴还可以这样包装

class UserRoleMng{

public void addRelation(user,role){

super.addRelation(user.getId,role.getId);

}

...

}

这样的设计看起来比原来的要好一点了,但是有一个问题是,按我的经验AbstractRelationManager很可能需要使用模版方法模式(templet method)来实现,这样不可避免的会违反依赖倒易原则(DIP)并降低代码的可读性,与我们的初衷有些背离。当然templet method也可以用代理类来代替,但是这样的实现在我看来不但复杂而且更不优雅。另一种代替的方式是不采用templet method而把对模版方法的调用实现在每个子类中,这样要求每个子类严格的符合编码约定,而且带来了拷贝代码的臭味。相比之下,我还是宁可选择在必要的时候templet method。

最后,我们有可能需要处理更复杂的关系,比如:

group------group-------user

| |---------user

| group-------group------user

| | |---------user

| |---------user

|---------user

user-group关系的一方,group是具有递归的层次结构的对象。这中情况下我们大概还需要从AbstractRelationManager继承一个新的抽象类

abstract AbstractRecurveRelationManager AbstractRelationManager{

protected List getId1ListById2Recurve(id2){

//递归方法id2对应的对象的子树并获得所有树节点的id1列表。

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有