欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

软件构造——实验三中的可复用性和可维护性

程序员文章站 2024-02-09 16:11:22
...

软件构造的lab3中有三个场景:

(1)值班表管理:安排员工值班,每天只能安排一个员工,且不能出现无人值班的情况。需要每天记录当天值班员工的信息。

(2)操作系统进程调度管理:单核CPU执行多个进程,每个时间只能有一个进程在执行,一个进程的执行可以被分为多个时间段,CPU可以闲置。

(3)大学课表管理:各周课表完全一样,进行周期性的重复,一个时间段内可以安排不同的课程,可以有时间段没课,一个教室可以承担课表中的多门课程。

共性:三个场景都需要在一段时间内执行一定的任务。

特性:场景1不能出现空白时间段,场景3在同一时间内可以有不同的任务进行。

它们都需要用到实现给定的接口IntervalSet的类CommonIntervalSet或是MultiIntervalSet。

我们需要实现以下几个方法:

public void insert(long start, long end, L label) throws IntervalConflictException;
public Set<L> labels();
public boolean remove(L label);
public long start(L label) throws NoSuchElementException;
public long end(L label) throws NoSuchElementException;

以CommonIntervalSet为例,来看看我是如何实现的:

首先需要构建一个合理的数据结构来存储Set的相关信息,我根据模板的提示,选用了两个Map映射来存储:

private final Map<L, Long> startMap = new HashMap<>();
private final Map<L, Long> endMap = new HashMap<>();

在insert函数中直接插入即可:

startMap.put(label, start);
endMap.put(label, end);

但是考虑到应用时,不能有重叠区域,所以在插入前需要进行判断,并且抛出相应异常:

		if (startMap.containsKey(label))
			return;
		boolean[] interval = new boolean[MAX];
		for (L l : labels()) {
			long s = startMap.get(l);
			long e = endMap.get(l);
			for (int i = (int) s; i < e; i++)
				interval[i] = true;
		}
		for (int i = (int) start; i < end; i++)
			if (interval[i] == true)
				throw new IntervalConflictException("The interval exists.");

剩下几个方法的实现相对简单,就不一一列举了。

然后来看MultiIntervalSet,它相比CommonIntervalSet,多出来一个功能:一个label可以拥有多个时间段。那么之前的Map映射显然是无法满足这个要求了,我还是根据模板,采用了两个List来进行存储(这里用了protected而不是private是为了方便之后扩展其子类,但在一定程度上丢失了其封装性):

protected final List<L> labelList = new ArrayList<>();
protected final List<Long> valueList = new ArrayList<>();

和之前一样,检查完重叠区域后就可以直接插入:

		labelList.add(label);
		valueList.add(start);
		valueList.add(end);

获得label及其时间段的方法是以随机读取方式遍历链表,n代表label,2n和2n+1代表其时间段。

这是intervals方法的实现:

	public IntervalSet<Integer> intervals(L label) throws NoSuchElementException, IntervalConflictException {
		if(!labelList.contains(label))
			throw new NoSuchElementException("No such label.");
		IntervalSet<Integer> ans = new CommonIntervalSet<>();
		int count = 0;
		for(int i = 0; i < labelList.size(); i++) {
			if(labelList.get(i).equals(label)) {
				ans.insert(valueList.get(2 * i), valueList.get(2 * i + 1), count++);				
			}
		}
		return ans;
		//throw new RuntimeException("not implemented");
	}

以上便是两个可复用可维护的实现了IntervalSet的类的介绍。

实验用例:

对于任务一排班管理系统,我们新建一个DutyIntervalSet作为CommonIntervalSet的子类,并不需要额外添加很多新方法,我这里仅添加了一个判断set是否已满的函数:

public class DutyIntervalSet extends CommonIntervalSet<Employee> {
	public DutyIntervalSet() {
		
	}
	
	public boolean noBlank(long max) {
		boolean[] duty = new boolean[(int) max];
		for(Employee i : labels()) {
			for(int j = (int) start(i); j < end(i); j++)
				duty[j] = true;
		}
		for(int i = 0; i < max; i++)
			if(!duty[i])
				return false;
		return true;
	}
}

之后便是在操作类DutyRoster中实现各种功能,然后由DutyRosterMenu类显示菜单和读取信息,最后由一个DutyRosterApp类主函数调用运行。

以上为本篇文章的全部内容。

相关标签: 软件构造 java