思考一个问题:某个布尔值在系统中应该显式定义还是应该隐式推导?
比如说,人和兽都是动物,业务规则是:直立者即人,爬行者为兽。
那么 在“动物”表中, 除了要有 “行走方式” 这个字段,要不要再搞一个 “是人是兽” 字段?
隐方:不必了。通过站立方式已经可以推导出是人是兽了,再搞一个字段就是冗余了,众所周知,冗余有很多坏处。
显方:我觉得应该搞一个“是人是兽”的字段。先不说冗余的问题,先说搞一个这样的字段有哪些好处。
1. 最重要的一点,是可以帮助业务逻辑之间解耦,降低系统复杂度。 比如说,系统里判断一个动物能否说话时,先要判断这个动物是人还是兽,而要判断动物是人还是兽,要先判断它的行走方式是否为直立。 这样的话,“能否说话” 就依赖了 “是否直立行走”,如果这种依赖关系多了,这些关系就会在系统中形成一个网状结构,很复杂。而如果我们显式地搞一个 “是人是兽” 的 Mediator,网状结构就可以退化成星形结构,这样可以增强系统的可维护性。
2. 业务逻辑之间解耦后,还可以减少公司里业务专家的压力。很多程序员,尤其是新来的五谷不分的程序员,并不知道直立的就是人,趴着的就是兽。要了解这一点,他们就得去问业务专家,即老工程师或者产品经理,这个代价可大可小。他也可以去查文档,但按我们的现状,文档未必完整,而且篇幅巨大,查起来也非常费劲。
隐方:对你的第二点我很赞同,但关于第一点,我觉得还是设计技巧的问题。你在业务层写一个接口用于判断“是人是兽”,不就可以了吗?而且这样还可以封装判断的细节,当判断规则改变时,接口的调用者可以不必改写代码。
显方:这么看来至少你赞成搞一个“显式”的接口了,只不过是放在业务层;这样既可以实现业务逻辑的解耦,又可以避免数据库中的冗余。
隐方:是啊,很完美吧?
显方:但你的想法需要一个大家定一个规矩:即所有人都必须通过个接口来进行人兽判断。这在代码不多、并且软件复用思想深入人心的小型团队里倒是很适用,因为这个规矩很容易执行;但在大型团队里,这个规矩很难执行;因为很多人对业务层的重用并没有什么概念,他们会直接绕道去找数据库;而且即使他们愿意重用业务接口,在项目紧张时也懒得去找相应的接口规格,因为他们根本不知道这个接口是否存在,也不知道应该去找谁问这个问题。
隐方:这是另外一个问题了,主要跟软件过程有关系,或者可以借鉴SOA实践中的一些思想,我们另开一个话题再聊吧。
魔力猫咪 写道我个人赞成隐式推导,一般不建议定义布尔字段。
因为绝大多数的这种判断,都是需要进行一些比较计算的。如果设定一个字段来存这个值,那么在参与判断计算的其他字段发生变化或者计算公式变化的时候,就必须更新这个布尔值。如果考虑不到位,没有更新,那么就会造成错误。为了及时更新,编码里面判断计算的调用到处都是。只要相关字段有了变化,就得重新计算。至于什么时候读取这个字段就不知道了。也许永远不会被读取。所以从这点上说,定义一个布尔值字段是得不偿失的。既增加了大量的无用计算,又引入了忘记计算造成BUG的风险。触发器倒是可以保证不会忘记计算,但是性能损失很大。如果是频繁更新的表,触发器一多,那么插入修改的效率就非常低了。
我认为如果要定义布尔值字段,那么就要求这个字段不用任何判断计算。
我认为LZ提问的动物表问题,不应该设定是否“人”这种字段判断。而是应该使用继承关系进行处理。至于提出的程序员问题,这个不是设计问题而是管理问题。管理混乱,那么插再多的这种字段也没用。除了搞乱数据库结构,没任何好处。建议对新人采用老带新的办法。编码前一定要进行设计,搞清楚了要建哪些类、有哪些接口哪些调用再编码。最好编码前就把测试写出来。新人写完设计(当然不是那种骗客户的设计说明书)后老人一定要进行审核。确认没有重复编码和层次混乱。
最后还要说一下。LZ提出这个问题考虑的层次有点低,什么都放在了数据库层次考虑。这样会把太多的业务逻辑引入到数据库里面。建议尽可能把业务放到应用层而不是持久层。
27 楼 miaow 2010-09-17 hibernate在同表保存继承的实现已经如此被鄙视了么?
如果能肯定永远不会有人和动物之外的实现类,肯定永远有相应属性、方法或者接口,那么怎么实现都行。
借数据库的一个实现方式说,那个标志属性本身和是否为空的函数索引没啥区别。
不肯定的话,hibernate在数据库层面用标志位、对象层面用多实现类的方式,个人认为是个概念清晰的好方式。不用hibernate也可以参考这个思路。 28 楼 miaow 2010-09-17 隐式的说法很值得怀疑,是人是动物可以在运行时转换的设计?GSM。 29 楼 gaoc121 2010-09-19 为什么不再setter中书写逻辑呢?
当传入是人是兽时,就可以在其setter中确定了,再为行走方式赋值
这既可以减少冗余,又可以统一实现了吧,再新的新手,不会连实体有哪些属性都不清楚把 30 楼 miaow 2010-09-19 gaoc121 写道为什么不再setter中书写逻辑呢?
当传入是人是兽时,就可以在其setter中确定了,再为行走方式赋值
这既可以减少冗余,又可以统一实现了吧,再新的新手,不会连实体有哪些属性都不清楚把
我想你和很多人一样被楼主带沟里了。OO的角度看问题,用标志位干啥。
按照这个话题,比较适当的方法是人、兽作为抽象类动物的两个实现类,而不是一个标志位。两个类分别实现自己的.运动()方法。实例创建采用工厂接受一个表示类型的参数。
多究一点,运动方法可以用策略模式,动物类的对应属性应该是个集合,表现可以有多个运动方式。