日期:2014-05-20  浏览次数:20737 次

真实设计案例:出了一个非常不满意的设计,但想不到改进方案
最近在做一个模块的设计,其中核心数据模型的类图,
画出来让我觉得十分别扭,如下图:



整个模块的需求概述如下:

1、该模块接收其它模块发送的信息,称为 事件,
2、事件 在经过证实后,被转成 告警,告警 包含事件的所有信息, 并扩展发生次数、最后发生时间、状态等信息。
3、假定 事件 有N个属性,其中
  3.1 M个属性联合起来,可以作为 事件 的识别特征,如果 事件 和 告警 的识别特征相同,则认为 事件 和 告警 是匹配的
  3.2 K个属性上可以设置过滤条件, 符合条件的 事件 将被模块直接丢弃
4、该模块收到 事件 后,首先根据3.2的要求进行过滤
5、没有被滤掉的 事件,再根据3.1的要求判断是否有匹配的 告警
  5.1 有匹配 告警, 则修改 告警 的发生次数
  5.2 没有匹配的 告警, 则创建新的 告警


我的设计思路:

三个接口:
IMatchInfo: 满足需求3.2,该接口的所有属性都是可以设置过滤条件的
IEvent: 继承自IMatchInfo,扩展事件特有的属性,如:序号SN
IAlarm: 继承自IEvent,扩展告警特有的属性,如:次数Repeat

三个类:
AbsMatchInfo: 抽象类,实现IMatchInfo接口,这个类的主要目的是实现sameAs方法,也就是实现需求3.1
Event: 继承自AbsMatchInfo并实现IEvent接口
Alarm: 继承自Event并实现IAlarm接口




如果我稍微简化一下,去掉一个抽象类和继承关系,画成下图:


这样设计图稍微好看一点,
但sameAs方法和getSet方法要在Event和Alarm两个类上写重复实现了,
感觉也很不爽。


再改一下,去掉接口之间的继承关系,将类之间的继承改成聚合:


这样,继承关系混乱的情况得到了改善,
但IAlarm无法当作IEvent用,会导致其它模块的接口必须发生改变(原来一个方法就可以,现在要改成两个方法),
而且IEvent和IAlarm无法直接比较,会导致其它代码变得复杂。




这可是新鲜出炉的真实设计案例,
大牛、小牛,高手、低手,新手、老手,菜鸟、老鸟,
大家有什么更好的想法,欢迎讨论?

------解决方案--------------------
嘿嘿,不要为了设计而设计。

我觉得,取掉接口之间的继承关系,实现类之间还是用继承关系。
让实现类实现多个接口,这样可以复用上级的实现,也可以通过接口进行约束.
------解决方案--------------------
传不上图片,小菜鸟说2句~
IMatchInfo,IEvent,IAlarm 3个接口保持不变,用于约束。
然后 创建AbsAlarmAdapter实现IAlarm接口与IEvent接口(双向适配)
public abstract class AbsAlarmAdapter implements IEvent,IAlarm{
private IEvent event;
public AbsAlarmAdapter(IEvent event){
this.event=event;
}
//以下IEvent接口方法的实现默认为委派,IAlarm接口的方法由该类的子类实现
}
初学,有什么设计不合理的请指正,嘎嘎~
------解决方案--------------------
IMatchInfo 不要写成接口,
写成一个抽象类MatchInfo,
IAlarm IEvent 仍为接口.

AlarmImpl类需要继承MatchInfo,实现IAlarm 
EventImpl类需要继承MatchInfo,实现IEvent 


菜鸟发言,, 高手莫笑
------解决方案--------------------
我觉得过滤可以参照 web 过滤的方式。把 IEvent 当作参数传过去。然后直接返回 boolean。
警告和事件不能继承。按照需求,我觉得应该做一个特征码的类,用特征码和警告组合。
而IEvent应该有一个返回特征码的方法。(如果特征码可以用long ,String表示,那可以省略这个类)
然后做一个Map<特征码,警告>。
通过Event返回一个特征码,在map中查找,如果没有 就用这个特征码建立一个警告。然后,改写警告的信息,次数,最后的时间。如果map 中 存在 警告,就直接改写。
------解决方案--------------------
先搭一个控制类,用来把验证规则抽取出来,再做一个适配器类,用来把事件转化为告警,我觉得事件和告警完全没有必要
做成一个接口,只不过是两个最简单的PO而已(当然也可以是接口,不过觉得这不重要)
------解决方案--------------------
事件和告警,在案例中就是实体Bean,需要定义接口吗?
我认为没有必要。
新手发言,欢迎拍砖。