在设计商品模块的时候,有一个需求是某一些商品是不能参加活动的。这个时候设计商品模型的时候就又两种选择:
将限购这个属性放到商品模型上,归商品模块维护
商品模块不管这个限购属性,由活动模块记录限购,维护一份限购商品Id表
个人觉得这两种方式都可以,但是如果把限购这个属性放到商品模型上得话,以后这种特殊属性越来越多的话,会导致商品模型无限膨胀。所以如果由促销来管理这个关系的话,商品模型上就只有一些简单的属性,这个基础服务就会更加的干净。
请问有没有一些经验或者准则可以参考一下?谢谢。
在设计商品模块的时候,有一个需求是某一些商品是不能参加活动的。这个时候设计商品模型的时候就又两种选择:
将限购这个属性放到商品模型上,归商品模块维护
商品模块不管这个限购属性,由活动模块记录限购,维护一份限购商品Id表
个人觉得这两种方式都可以,但是如果把限购这个属性放到商品模型上得话,以后这种特殊属性越来越多的话,会导致商品模型无限膨胀。所以如果由促销来管理这个关系的话,商品模型上就只有一些简单的属性,这个基础服务就会更加的干净。
请问有没有一些经验或者准则可以参考一下?谢谢。
我基本同意 @边城 的方法。
商品,活动,限购都是需要记录的事实。关键问题是“限购”应该怎样表示。
由于限购本身还可能包含其他属性,比如限购日期等等,所以不是单单一个关联表(多对多关系)就能解决的。
有两种方法可以记录限购:1)记录不限购的商品、活动2)记录限购的商品活动
如果限购的商品活动数量相对较小,方法2)更合适。
Product (ProductId, ...)
Activity (ActivityId, ...)
PurchaseRestriction (ProductId, ActivityId, StartDate, EndDate,...)
你的疑问:
1. 这张映射表,属于哪个模块去维护
商品、活动不是相互独立的,PurchaseRestriction 恰恰表示了它们之间的联系。
PurchaseRestriction 既跟Product相关,又跟Activity相关。不是简单的“谁的属性”。
很多人设计class时使用循环引用,比如,Product 拥有 RestrictedActivities 集合,Activity 拥有 RestrictedProducts 集合。
你心里也有类似的疑问,一方面觉得限购是一个事实,只应该放在一个地方;另一方面,感觉限购既是Product的属性,又是Activity的属性。
我觉得,这是面向对象的一个缺点,“对象拥有属性,属性必须属于某个对象”这个思想的根源是认为所有东西都是树状结构的。
这跟树形数据库犯了同样的错误,后来出现网络数据库。网络数据库可以表达复杂的结构,但是过于复杂。
关系数据库的出现,解决了树形数据库和网络数据库的问题。关系数据库是基于集合论和一阶谓词逻辑的模型,可以完美地表达各种结构。
"模块化"当然很好,合理的模块化减少了程序各模块之间的耦合。
但是,一个系统最大的耦合往往是程序和数据的耦合。数据的结构变了,程序必须跟着变。
因此,规范的数据库设计比应用程序的模块化更重要。
你把商品和活动分到不同的模块,一方面提高了抽象级别,模块化,另一方面割裂了它们的联系。虽然模块多了,但模块间的交互更复杂了。
你的问题没有完美的答案,有3个解决方案:
a) 商品模块去维护
b) 活动模块去维护
c) 单独的模块去维护。
2. 上面提到的(商品是否能参加活动,商品限购属性),我觉得第一个是可以归为商品固有属性,第二个可能通过一张映射表来记录(因为限购商品毕竟是少数)
"商品是否能参加活动"可以由PurchaseRestriction推导出,不需要这样的属性。
在程序里,也许有某个类,它有一个属性 CanTakePartInActivity. 但是数据库不能这样设计。
一般情况下,建议采用商品和活动分表记录,然后通过一张关系表来建立联系,这样不管从商品找活动还是从活动找商品都会比较方便。对于近期活动需要快速读取的情况,甚至可以针对活动单独建立缓存数据,以提高读取效率。
具体情况具体分析,如果商品任何活动都不参加,则直接放在商品表中可矣,但如果某种商品只是某次活动不参加,而别次活动又有可能要参加,则必须另外建立一个商品活动表。
或者将商品分类,某次活动某几类商品参与,则需要建立一个活动商品分类表,但也可能这次活动这些分类商品参与,而又要排除某几件特殊商品,还是要分析这些被排除的商品是否有共性?如果有共性,则加分类标签,如果完全是凭店主个人喜好随机摘除,则再加一个排除表。大概就是这么一个思路。