再说继承关系
Teddy的NBear终于开始实现继承,对我来说又多了一个真正可以探讨问题的同行。但是Teddy没有实现一类一实体的方案,这令我非常失望。我曾在这一方案上付出过太多的艰辛,是因为我知道这种方案的真正价值。在ER模型理论中,关键的元素就是实体和关系,对于实体来说,重要的子元素是属性,属性的共享可以催生抽象从而导致继承。对于关系来讲,关系包括基数关系、依赖关系和结构关系,其中最主要的结构关系就是特化/泛化关系,映射到OO就是继承。在我的上一篇文章描述过这样的关系。
前段时间交付了一个系统。由于该系统只是整个大系统中的第一个子系统,紧随其后还有三个子系统。为了将每个子系统都公用的部分能够方便抽取出来,所以采用了一个公共域。该公共域的主要功能是:
1. 认证
2. 权限及授权
3. 日志
4. 即时消息
于是就有了以下的设计(省略了日志部分和即时消息部分):
这里有一个比较罕见的三元关联关系:权限、区域和权限所有者。目前这里的区域是指行政区域,省、地市、区县,等等,当然在设计上完全可以想象成一个任何的范围对象,表示该权限在该范围内才有效。而权限仅仅只是一个字符串标识,例如system.management.usermanagement就表示用户管理权限,当然,权限不是一个动态概念,必须由系统需求来决定的,不过由于比较自由所以更容易维护。
相比之下权限所有者就比较复杂一点,包括两大类:第一类是用户,第二类是用户组。同时用户与用户组又是关联关系,而运行时每个用户所执行的权限是用户自己的权限加所在的用户组的权限的并集。所以,第一层继承是从权限所有者到用户和用户组的继承。另外,用户分做两类:一类是本地用户,即在系统内有效的用户,由本系统认证;第二类是单点登录用户,或者称为门户用户,与企业其他应用系统共享一套用户认证。
日志系统比较复杂。除了登录日志、异常日志外,所有的改动都要有记录。所以,就有了从日志到登录日志、异常日志、改动日志的继承关系,同时也有了从改动日志到插入日志、编辑日志、删除日志的继承关系。
是否一定需要导入复杂的继承关系?我认为是必不可少的。虽然有的人也采用没有继承关系的方案解决得很好,但是对后续的设计一定比我复杂很多。例如,用户对象将会分散到系统的各个角落,对用户的抽象令用户对象不再关注认证方式和认证的信息。这符合我的原则:继承关系存在的唯一理由就是关系共享导致的抽象。而日志的共享,是依据一个从业务实现和表现层所带来的对抽象日志的管理。这就是:每一个日志被记录后,受配置所控制,可以通过Email、SMS或者其他任何可以采用的方式即时向外发布。
系统运行一段时间以后,用户希望将消息系统一日志结合起来,用户可订阅一些日志作为即时消息。这个提议非常好,立即被我接受。于是,我需要从用户那里派生出一个GhostUser出来,将这个Ghost用户与具体的日志进行关联。当然,GhostUser是无法登录的,仅仅是作为即时消息系统中的占位用户。于是就有了以下的设计,呵呵,很容易看出来,以前的数据表不需要任何修改,如果用户系统中有大量的实际数据,那么这次更新也就不会造成任何麻烦:
如果你采用单表,或者一个具体类一个表,能很清爽地解决么?
重复一下我以前文章中的论点:
1.单表实现的继承是回避了继承关系,事实上是采用其他的关系替代继承关系,所以不要称之为“单表实现继承”;
2.每个具体表一张表实现的继承在某种程序上实现了继承,但是这种继承的交通非常有限,不足以很灵活地处理复杂的关系。