Lab3实验过程记录

        截止目前,已经完成了3.6节及之前的大部分实验内容,为app实现所需要的set类(在包set中)已经全部设计实现,为了扩展IntervalSet和MultiIntervalSet所需要的delegation委托类也全部实现(在包del中);app中,完成了DutyRosterApp的全部设计,能正常实现全部功能。整个实验的文件目录暂时如上。

        本次实验着重考察面向可复用性和可维护性的程序设计。对于需要实现的三个程序app实例,可以抽象出具有共性特性的抽象类IntervalSet和MultiIntervalSet,用于维护一系列时间段和label的关系。在此基础上,再对实例问题的特性部分进行扩展,具体实现。通过这样的设计方式,能很好的实现代码复用,且程序更加易于维护。

        以下是实验过程中的一些问题及思考:

1. 对NoPeriodic条件的理解

        3.1节中,给出了三个app实例的应用场景。其中第三个app,课表管理程序中,允许时间段以一定的周期循环(课程可以以一周为单位进行循环)。这个条件区别于前两个app中并不允许(或者说需求)时间段具有循环性,使得intervalset的具体实现特性需要包括NoPeriodic的条件。此后的设计过程也明确要求需要将该条件作为特性实现。

        但是,单从设计课表管理程序本身出发,并没有对这个条件有特别显示的要求。设计要求中提到:假设其各周的课表都是完全一样的(意即,同样的课程安排将以“周”为单位进行周期性的重复,直到学期结束)。那么实际上实现的课表每周都是完全一样的,查看任意一天的课表,实际上只需计算天数模七后对应的第一周天数下的课表,这样的处理将使得并不需要时间段显式的“循环性”表示。

        最终实现的过程是,为我记录时间段使用的Period类加入了一个额外的成员,用于标记是否可周期性。对应的委托类将会在插入的同时将其设置为不可周期性。这个实现只是简单的表示了“周期”特性,具体的应用价值不大(在该app中的需求不大)。如果要实现更复杂的周期性表示,可以在Period类的基础扩展子类,添加额外的成员,用于记录循环周期等信息。

        或许可以考虑在题目中添加额外的条件(如要求科目可以只出现在部分周,有更加复杂的“周期性”情况),使得该特性的设计更加有意义。

2. MultiIntervalSet和IntervalSetSet之间的关系

        3.2节中,要求实现MultiIntervalSet和 IntervalSetSet两个类,用于实现最基本的维护一系列时间段和label关系的功能。实验题目中给出了一个问题:考虑 MultiIntervalSet和 IntervalSetSet之间的共性和差异,它们二者可以进一步抽象形成一个更高层次的 ADT 吗?

        两者之间确实有相当程度的共性,例如,两者可以以完全相同的成员进行实现:一个label的set集合,以及一个label到List<Period>的映射map。两者最大的差异性,主要是体现在MultiIntervalSet要求一个label可以与多个Period联系,而IntervalSetSet只允许与一个Period联系。

        那么,如果将MultiIntervalSet作为父类,IntervalSetSet使用继承,在其基础上重写insert函数,增加对insert过程的限制条件,这两个类就能很好的联系起来了。但,考虑到两个类之间实现的类方法有一定的差距(如上图所示),这两个类之间并不适合直接使用继承。

        经过思考得到的最终结果是,不考虑两者的更高层次抽象,也可以通过委托的方式增强两者之间的关系,提高代码复用性。如上图中,MultiIntervalSet中包括了一个 IntervalSetSet类的DelCommmonIntervalSet成员。这个DelCommmonIntervalSet类是对CommmonIntervalSet的继承子类,重写其Constructor,移除防御性拷贝,使得该类能够管理来自外部的set和map。这样,就可以通过委托使用大量的CommmonIntervalSet方法,只需简单的重新编写insert方法,补足其余需要额外实现的方法即可。

3. 使用委托实现特性设计

        3.4.2节中,对特性设计给出了6中可能的实现方案。可以很明显的看到,给出的前四种方案都不能在保护抽象共性的同时很好的解决大规模的特性实现,使得代码复用性有限,不便开发。第五种方案使用了委托模式,第六种方案使用了装饰器模式。我最终采用了委托模式,很好的实现了特性设计。

package set;

import java.util.List;

import del.NoBlankIntervalSet;
import del.NoBlankIntervalSetImpl;
import del.NonOverlapIntervalSet;
import del.NonOverlapIntervalSetImpl;
import del.NonPeriodicIntervalSet;
import del.NonPeriodicIntervalSetImpl;

public class DutyIntervalSet<L> extends CommonIntervalSet<L>
							 implements NoBlankIntervalSet<L>,
										NonOverlapIntervalSet<L>,
										NonPeriodicIntervalSet<L>{
				
	private NonOverlapIntervalSet<L> nois = new NonOverlapIntervalSetImpl<L>(this.labels, this.periods);
	private NoBlankIntervalSet<L> nbis = new NoBlankIntervalSetImpl<L>(this.labels, this.periods);
	private NonPeriodicIntervalSet<L> npis = new NonPeriodicIntervalSetImpl<L>(this.labels, this.periods);
	
	
	@Override
	public boolean insert(long start, long end, L label) {
		if(!this.labels.contains(label)) {
			if(!nois.insert(start, end, label))	return false;
			npis.isNonPeriodic(start, end, label);
			return true;
		}
		return false;
	}

	@Override
	public boolean isNonPeriodic(long start, long end, L label) {
		if(this.labels.contains(label)) {
			for(Period period : this.periods.get(label)) {
				if(period.getStart() == start && period.getEnd() ==end)	return period.isPeriodic();
			}
		}
		return false;
	}

	@Override
	public List<Period> checkNoBlank(long startTime, long endTime) {
		return nbis.checkNoBlank(startTime, endTime);
	}

}

        以值班表管理程序需要实现的DutyIntervalSet为例,代码如上所示。可以很明显的看出,使用委托模式大大降低了代码量,提高了复用性。在实现特性相关的委托类后,只需要按照需求对原MultiIntervalSet或 IntervalSet实现接口扩展即可。只需额外编写少量的代码,复用委托类实现特性内容。

        就具体的实现过程来说,对于每一个委托类,都可以使用Constructor在初始化时向其传递set和map成员,使得其可以管理委托它的set类成员。在这些成员的基础上编写对应的代码进行成员操作,以实现需要满足的特性方法。在需要满足这些特性方法的类中,就可以简单的声明委托,传递成员,然后依靠这些委托类来实现。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值