实现计划项app辅助类设计
面向复用的设计:R
这个任务中我们需要实现不同的资源类型。由于不同的资源之间类型差异比较大,因此我们面向不同的类单独设计资源即可。
航班应用中的资源是“飞机”,属性包括飞机编号、机型号(A350、B787、C919 等)、座位数、机龄(例如 2.5 年)。因此这个类需要有4个属性,它们的表示不变性为:
private final String flightNum;
private final String modelNum;
private final int seatNum;
private final float year;
// Abstraction function:
// 以飞机编号、型号、座位数、机龄来映射一个飞机
// Representation invariant:
//
// Safety from rep exposure:
// 所有属性都定义成private和final保护属性引用不变
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
同时在这个类中我们还重写了equals函数用来判断资源的相同,它的具体描述为:
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj instanceof FlightR) {
FlightR a = (FlightR) obj;
if(a.getFlightNum().equals(this.getFlightNum())) {
if(a.getModelNum().equals(this.getModelNum())) {
if(a.getSeatNum() == this.getSeatNum()){
if(Math.abs(a.getYear() - this.getYear()) < 0.001) {
return true;
}
}
}
}
}
return false;
}
同时还为飞机资源提供了几个get方法以及重写了toString方法。
高铁应用中的资源是“车厢”,属性包括车厢唯一编号、类型(商务、一等、二等、软卧、硬卧、硬座、行李车、餐车)、定员数(例如100人)、出厂年份。为了实现这个资源类,我们同样设置了4个属性,它们的表示不变性为:
private final int carNum;
private final String type;
private final int personNum;
private final int year;
// Abstraction function:
// 以火车车厢编号、类型、容量、生产年份来映射一个火车车厢
// Representation invariant:
//
// Safety from rep exposure:
// 所有属性都定义成private和final保护属性引用不变
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
和前面的描述一致,我们同样重写了equals方法,这个类中同时也设置了get方法以及重写了toString方法用于辅助执行功能。
课表应用中的资源为“教师”,属性包括身份证号、姓名、性别、职称。因此我们设计了4个属性,它们的表示不变性如下:
private final String idNum;
private final String name;
private final String gender;
private final String title;
// Abstraction function:
// 以教师编号、名字、性别、职称来映射一个教师
// Representation invariant:
//
// Safety from rep exposure:
// 所有属性都定义成private和final保护属性引用不变
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
这个类中的重写equals方法与前面提到的类似,因此不做重复。同样,为了更好完成后续功能,我们也设计了get方法以及重写了toString方法。
在这个类中,为了辅助后面实验的书写,我们还设置了多个资源类和单个资源类,这样的设计能够极大提高程序复用性。此处我们以单个资源设计,涉及到泛型的设计举例,如下:
private R sre;
// Abstraction function:
// 保存单个资源来展示资源情况
// Representation invariant:
//
// Safety from rep exposure:
// 所有属性都定义成private和final保护属性引用不变
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
/**
* 得到资源信息
* @return 返回单个资源
*/
public R getResource(){
return this.sre;
}
/**
* 增加资源
* @param resource 输入资源
* @return 返回true
*/
public boolean addResource(R resource) {
this.sre = resource;
return true;
}
面向复用的设计:Location
这个任务需要完成位置类的设计。一个“位置”对象的属性包括:经度、纬度、名称、是否可共享使用。因此和前面提到的设计思路一致,我们需要设置4个属性,它们的表示不变性如下:
private final float longitude;
private final float latitude;
private final String name;
private final int share;
// Abstraction function:
// 以经度、纬度、名称、是否可共享来表示一个位置
// Representation invariant:
// share只能是0或者1
// Safety from rep exposure:
// 所有属性都定义成private和final保护属性引用不变
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
这个类中因为设计过程中根据地址的名称来对地址进行判断,所以需要提供得到地址信息方法,具体如下:
/**
* 得到位置信息
* @return 返回位置名称
*/
public String getLoc() {
return this.name;
}
同样这个类也重写了toString方法用来返回位置信息。
位置类和资源类一样,为了辅助后续功能的实现,我们必须设置接口和具体实现,方便方案5的设计,即利用委托机制,这部分内容在后面会详细描述。这里我们以两个位置为例进行描述:
private Location start;
private Location end;
// Abstraction function:
// 以start、end保存位置信息
// Representation invariant:
//
// Safety from rep exposure:
// 所有属性都定义成private防止属性直接泄露
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
@Override
public boolean setLocations(Location start,Location end) {
this.start = start;
this.end = end;
return true;
}
@Override
public Location getStart() {
return this.start;
}
@Override
public Location getEnd() {
return this.end;
}
面向复用的设计:Timeslot
这个任务主要是为了实现构建一个时间对。一个单独的“起止时间对”设计Timeslot类,它是一个带有起始时间和结束时间的ADT,应包含日期(年/月/日)和时间(时/分),符合yyyy-MM-dd HH:mm的语法规则。
因此这个类设计过程中需要将输入的字符串转化为时间进行存储。具体还需要满足格式的需求。具体的属性和表示不变性如下:
private final Calendar start = Calendar.getInstance();
private final Calendar end = Calendar.getInstance();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
// Abstraction function:
// 以两个时间点来表示一个时间对
// 其中start是开始时间,end是结束时间
// Representation invariant:
// start和end是Calendar的实例,同时限制了格式
// start的时间小于end的时间
// Safety from rep exposure:
// 所有属性都定义成private和final保护属性引用不变
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
为了展示具体的转化过程,这里提供构造函数进行分析:
/**
* 构造函数,输入两个字符串,转化为一个时间对
* @param start 开始时间的字符串表示
* @param end 结束时间的字符串表示
* @throws ParseException 解析格式不符合抛出异常
*/
public Timeslot(String start,String end) throws ParseException {
this.start.setTime((Date) format.parse(start));
this.end.setTime((Date) format.parse(end));
checkRep();
}
同样这个类也需要get方法和toString方法对信息进行展示。
这个类在设计完成之后还需要配合位置类进行设计。因为设计过程中我们在火车计划项输入的时间数和位置项一样的,而飞机和课程时间数都是一个时间对,因此我们需要设计一个单个时间对类和多个时间对类。此处我们以多个时间对为例:
private List<Timeslot> times = new ArrayList<>();
// Abstraction function:
// 表示资源有多个时间对
// Representation invariant:
// 时间对的列表不能为空
// Safety from rep exposure:
// 所有属性都定义成private保护属性不直接对外泄露
// 对于返回可变类型的对象,使用防御式拷贝的方式进行保护,避免表示泄露
@Override
public boolean setTime(List<Timeslot> times) {
this.times = times; //指向同一个引用
return true;
// this.times.addAll(times); //复制所有的值
}
/**
* 得到多个时间对列表
* @return 返回时间对的列表
*/
public List<Timeslot> getTime(){
return this.times;
}