在实验三中,我们写了两个接口
IntervalSet<L>
MultiIntervalSet<L>
我们定义了时间段类Interval
private final long start;
private final long end;
在Interval中保存的是一个时间段的开始时间与结束时间
对于两个接口,写了相应的实现
CommonIntervalSet<L>
private final Map<L,Interval> intervals = new HashMap<>();
CommonIntervalSet所实现的主要功能是管理标签L到时间段Interval的映射关系。每个标签L只能对应一个时间段。
如:在安排值班时间时,每个人只安排一个时间段。
在CommonIntervalSet<L>中,我们给出了一种方法,得到标签L label对应的时间段
public Interval getInterval(L label)
CommonMultiIntervalSet<L>
private final Map<L,IntervalSet<Integer>> intervals= new HashMap<>();
CommonMultiIntervalSet实现的功能是管理标签L到时间段集合IntervalSet<Integer>的映射关系。IntervalSet<Integer>即第一个接口,这里我们是用Integer类型代替抽象数据类型。每个标签L映射到一个时间段集合,即每个标签可以对应多个时间段。
如:进程执行时,执行时间并不是连续的,因此一个进程可能对应多个时间段。
在MultiCommonIntervalSet<L>中,我们给出了一种方法,得到标签L label对应的时间段的集合IntervalSet<Integer>
public IntervalSet<Integer> getInterval(L label)
介绍完前提,我们开始介绍本次实验中遇到的问题。
我们需要设计一个值班表排表的APP,DutyRosterSet
我们需要实现两种APP
第一种:同一个员工可以在两个不连续的时间段值班
第二种:同一个员工的值班时间必须是连续的
public class DutyRosterSet extends CommonMultiIntervalSet<Employee> implements IDutyRosterSet
public class DutyRosterSet extends CommonIntervalSet<Employee> implements IDutyRosterSet
很明显,对于第一种APP,我们应该继承CommonIntervalSet<L>类;对于第二种,我们应该继承CommonMultiIntervalSet<L>类
在DutyRosterSet中,我们需要实现以下功能
给定标签L label,以及时间段Interval time
我们要判断label是否指向时间段label
我们已经从CommonIntervalSet<L>和CommonMultiIntervalSet<L>中分别继承了
public Interval getInterval(L label)
以及
public IntervalSet<Integer> getInterval(L label)
此时,就给我们代码的实现带来了一定的问题。
当我们调用getInterval(label)的时候,由于继承的类不同,所返回的返回值的类型也不同,由于我们无法直接判断返回值是一个时间段的类型Interval,还是时间段集合IntervalSet<Integer>。这给我们判断标签label是否指向时间段time造成了很大困难。
因此,当已经实现第一种APP后,如果想实现第二种APP,此时我们不仅需要将继承的类由CommonIntervalSet<L>更改为CommonMultiIntervalSet<L>,还需要修改代码,这与我们要求尽可能高的复用性的要求相矛盾。
接下来,我们介绍一下针对这种问题的解决方案
2种方法,其实大同小异,都简单的写了一下
为了提高代码的可复用性,使我们可以更方便的根据不同要求,修改更少的代码。
我们考虑将判断的过程放入父类
第一种:保留差异性,在不同的父类中实现的方法,需要传入不同的参数
在CommonIntervalSet<L>中添加以下方法
public boolean belong(Interval a, Interval b)
在CommonMultiIntervalSet<L>中添加以下方法
public boolean belong(Interval t, IntervalSet<Integer> set)
此时,我们再判断标签label是否指向时间段time的时候,只需要调用
belong(time,getInterval(label))
由于在CommonIntervalSet<L>中,getInterval(label)返回的是Interval类型,而belong(,)要传入的参数正是Interval型
而在CommonMultiIntervalSet<L>中,getInterval(label)返回的是IntervalSet<Integer>类型,而belong(,)要传入的参数则是IntervalSet<Integer>型,此时分别对应相等
此种方法既解决了继承不同父类时返回值不同的问题,同时也保留了部分差异性,当我们所需实现的APP对某些差异性有针对性的要求时,可以使用此方法
第二种:直接使用同样的接口
在CommonIntervalSet<L>和CommonMultiIntervalSet<L>中添加同样的方法
public boolean belong(Interval t, L label)
此时,我们要判断label是否指向时间段time,只需要调用
belong(time,label)
这种方法就消除了差异性的问题,使代码有了更高的可复用性
同时,因为消除了差异性,只保留了共性的部分,使其他程序员在使用我们设计的接口时,更简单易懂
个人还是比较倾向于第二种方法的,毕竟我们写接口就是为了抽象出共性的东西,让我们可以更方便的反复利用
总结:
为了提高可复用性,应尽量减少继承不同父类时出现的返回值类型不同的问题,减少其个性的方法,增加其共性的方法,针对不同要求有不同实现,然后通过相同的接口,可以让我们的代码具有更好的可复用性