OPP4-6次PTA大作业总结
一,前言
经过前三次PTA,对java中的面向对象程序设计从陌生到熟悉。对于java中的单一职责原则,开闭原则,里氏代换原则等类设计原则也逐渐理解其中的意义。在后续的面向对象程序设计中也了解到一些类设计模式。例如:简单工厂模式,工厂方法模式,建造者模式,单列模式等。
在4-5次PTA大作业中,我的类设计还存在些不足,以下是我对这三次PTA作业的总结。
二,第四次作业
1.
第四次作业中,我意识到1-3次PTA作业的类设计中存在许多不合理的地方,于是我在第4次迭代中重写代码。
此次迭代中增加了题目的种类,涉及到继承与多态。还有不同题目有不同的判题方式。
以下是我类设计的思路:
DataHouse类:用于储存所有类型的对象。其中提供查找指定对象的方法。
DataMach类:用于储存正则表达式
ScanData类:用于输入信息并判断信息是否合法
PrintResult类:用于格式化输出所有学生的答题结果
ProssesingData类:用于处理所有信息,根据类间关系调整数据值
Answer,AnswerPaper,Question,Student等实体类用于储存并处理各自数据
由于该次迭代需要考虑题目种类,所以我对每一种题目都对应一个类,这些类都对应共同父类Question类。
2.类图、
3.遇到的问题
由于此次迭代需要用到继承和多态,遍历每一种题目时,不好判断该题目属于哪种题目类,而且不同题目类型有不同处理数据的方法,还有对不同题目类型按题号排序。
4.缺点
如上图我在processPaper()中用了大量的if语句,不符合代码规范。
5.改进
应该在写每一个方法时,应该减少for想循环和if语句的使用。例如在选择题类中,我定义了两种方该类的专有方法,来判断选择题类型的题型的正确性,而且在两种方法定义较为简洁规范。
public boolean checkAnswer(String myAnswer) {
boolean flag = true;
String[] myPerAnswer = myAnswer.split(" +");
for (String str : myPerAnswer) {
if (standerAnswer.contains(str)) {
continue;
}
else {
flag = false;
break;
}
}
if (myPerAnswer.length == 1 || myPerAnswer.length == 0) {
flag = false;
}
return flag;
}
public Boolean checkAnswerAllTrue(String myAnswer) {
boolean flag = false;
int num = 0;
int AllNum = getChoicesAnswer().size();
String[] myPerAnswer = myAnswer.split(" +");
for (String str : myPerAnswer) {
if (standerAnswer.contains(str)) {
num++;
continue;
}
else {
num = 0;
}
}
if (num == AllNum) {
flag = true;
}
return flag;
}
}
三,第五次作业
1.
在第五次作业中,进行了新一次的迭代。这次迭代要求是模拟一种家庭电路,其中需要模拟控制设备:分档调速器,连续调速器,开关,和受控设备:吊扇,白炽灯,日光灯。
由于这是模拟电路的第一次迭代。只需要考虑只有一个受控设备和一个控制设备串联的情况。但在类设计的布局中也应考虑后续的多个电器的串联和并联的情况。
以下是我的设计思路:
Datahouse类: 储存所有电路元件的对象数据
DataMatch类:储存所有匹配电路信息的正则表达式
Equipment类:改类为所有电路元件的父类
SeriesElectric类:串联电路对象其中包含Equipment类所有子类的对象。与Equipment类之间为组合关系,且继承于Equipment类
受控设备和控制设备等实体类都继承于Equipment类,其中包含将接受电压转化为对应数据的方法。
ScanData和ProcessingData类分别进行输入信息和处理信息的工作。
EquipmentFactory类——简单工厂类,通过接受电路元件名返回对应的元件对像
2.类图
3.遇到的问题
在PTA的样例测试中发现几处个别样例点错误
经过多次调试发现,如果开关于接地连接时无论快关是开闭还是闭合。点路都处于通路状态。
4.改进
在串联电路类添加判断整个串联电路的是否断路的方法。
其源码如下:
public int changeElectricCurrent() {
int ret = 1;
for (Equipment equipment : equipments) {
if (equipment instanceof Switch ) {
Switch switchEquipment = (Switch) equipment;
if (switchEquipment.getSwitchStatus() == 0) {
ret = 0;
setElectricCurrent(0);
break;
}
}
}
return ret;
}
通过遍历串联电路对象中的所有开关对象,并判断开关对象是否处于闭合状态。
四,第六次作业
1.
这次迭代要求在上一次寄出上添加了并联电路而且信息的输入方式也发生变化,同时添加了新的受控设备落地扇。还有添加了每个电路元件的电阻和整个电路的电流等信息
以下是类的设计思路:
此次迭代类图结构与上次一样。但在一些类的方法需要重写。
添加ParallelElectric类,该类为并联电对象与串联电路对象都与Equipment类为组合关系,且都继承于Equipment类。
添加FloorFan类,与其他电器类一样继承于父类Equipment类,另外在此次迭代中需要考虑电阻。所以在创建受控设备对象时初始化每种电器的电阻其中开关的电阻为0.
还有在串联和并联类中添加计算各自的总电阻方法
2.类图
3.遇到的问题
经过多次的PTA样例测试中发现,还有很多的边界值未考虑,导致很多样例点错误
经过多次调试后发现以下问题:
(1).电路中可能出现并联电路短路的情况。
(2).还有并联电路中的开关如果每条路都断开则整个电路视为断路。
(3).受控设备中的白炽灯和吊扇类中根据电压分别计算亮度和分速时由于电压是double类型在用电流乘以电阻计算该电路元件时可能存在误差。
(4).最后在输入串联电路设备时忽略了并联电路与电源直接相连的情况
4.改进
在计算并联电路的总电阻的方法中,添加特殊情况的电阻计算方式
public void setSumResistor() {
double sumResistorChange = 0;
boolean isShort = false;
for (Equipment equipment : seriesElectrics) {
SeriesElectric seriesElectric = (SeriesElectric) equipment;
seriesElectric.setSumResistor();
if (seriesElectric.changeElectricCurrent() != 0) {
if (seriesElectric.getResistor() == 0) {
isShort = true;
break;
}
else {
sumResistorChange += 1.0 / seriesElectric.getResistor();
}
}
}
if (sumResistorChange != 0 && !isShort) {
setResistor(1.0 / sumResistorChange);
}
else if (sumResistorChange == 0 && !isShort){
setResistor(-1);
}
else if (sumResistorChange != 0 && isShort) {
setResistor(0.0);
}
}
当该方法返回0时代表该并联电路短路,当返回-1时表示该并联电路断路。
在ProsessingData类中的ConnectingCircuit()方法中,将先计算电路的电流,再计算每个元件两端的电压的计算方式改为,串联电路的总电压乘以元件电阻与总电阻的比值。
改进代码如下:
public static void ConnectingCircuit() {
SeriesElectric seriesElectric = (SeriesElectric) DataHouse.A_SeriesElectric;
seriesElectric.setSumResistor();
double U = 0;
Equipment lastEquip = null;
int i = 0;
if (seriesElectric.changeElectricCurrent() == 0) {
return;
}
for (Equipment equipment : seriesElectric.getEquipments()) {
i++;
if (i == 1) {
lastEquip = equipment;
if (lastEquip instanceof ContinuousGovernor || lastEquip instanceof SplitSpeedGovernor || lastEquip instanceof Switch) {
lastEquip.setPinOne(seriesElectric.getPinOne());
U = lastEquip.getPinTwo();
}
else {
U = seriesElectric.getPinOne();
lastEquip.setPinOne(seriesElectric.getPinOne());
lastEquip.setPinTwo(lastEquip.getPinOne() - (U * lastEquip.getResistor()) / seriesElectric.getResistor());
}
}
else if (i > 1 && i < seriesElectric.getEquipments().size()) {
equipment.setPinOne(lastEquip.getPinTwo());
equipment.setPinTwo(equipment.getPinOne() - (U * equipment.getResistor()) / seriesElectric.getResistor());
lastEquip = equipment;
}
else if (i == seriesElectric.getEquipments().size()) {
equipment.setPinOne(lastEquip.getPinTwo());
equipment.setPinTwo(seriesElectric.getPinTwo());
}
}
}
用算电阻比值的方式可减少double类型带来的精度误差。
五,总结
经过这三次PTA的迭代,我对面向对象的类设计从逐渐熟悉到更加熟练的运用。在这段学习期间,也学到了许多类设计原则如组合模式,桥接模式,单例模式,工厂模式等类设计模式。我虽然了解这些类设计原则但还缺少许多实践。在PTA作业中运用的设计模式少,说明我在许多类设计模式中缺少理解,不知道某些设计模式在什么时候恰当的运用。
在新一轮的家庭电路迭代中也让我收获了许多,电路的串并联的连接和电路结构的变化这一个抽象问题,在代码中一 一实现过程中,使我的类设计能力进一步提高。
在4-6次PTA作业中,虽然我的类设计能力进一步提升,但是在定义方法的规范性也需要继续改进。