一.前言
1.知识点:
(1)因为需要使用子类所以应该还是要使用抽象类和接口来让子类通过父类提供的接口来实现它们需要的功能,就像第七次大作业中的设备父类的抽象showStatus函数还有control函数等等,因为不同的设备展现状态的方法不同而且不同的设备对电路的控制效果也不同,所以应该使用抽象函数,方便子类进行改写,并通过改写后的函数来实现对应的功能。
(2)采用多态来直接对父类进行操作,而不需要知道这是哪一个子类,因为子类虽然改写了父类的抽象方法,但在父类中这个抽象方法还是存在的,所以当一个未知类型的子类实例要调用这个抽象方法的时候可以直接用父类的类型来调用,特别是在第七次和第八次大作业中很多时候要将输入的设备信息保存下来,但不知道对应设备到底是什么设备,这时候就可以直接声明一个父类变量将具体的子类对象存储下来。
(3)使用子串操作来从输入信息中读取我们需要的信息,比如可以使用substring方法来去除第七次和第八次大作业中输入信息最前面的#以及最后面的],方便对需要的数据进行读取存储。
(4)采用 Scanner 类来读取用户输入,从控制台读取用户输入的信息,然后使用spilt方法来对输入信息进行分割并依次将有用的信息存储下来。
(5)递归函数的使用,因为电路中可能存在串联电路里面有串联电路,并联电路里面有并联电路的情况,对这种情况必须要不停的使用递归来将最底层的情况解析出来,然后再一层层的往外进行解析,最后才能得出正确的结果。
2.题量:
这次虽然只有两次大作业,但题量毫无疑问是最大的,因为这两次大作业的难度经过前面几次的难度递增已经来到了一个非常可怕的层次,首先是解答的思路,如果前面的设计思路不错的话可能会稍微轻松一些,但如果你前面的设计思路都是那种靠不停一点点填错填出来的话就相当于废了,因为互斥开关加入会让整个电路结构变的非常复杂,如果前面没有考虑到那么深的话很可能要全部推翻重新写。其次就是最后的测试点调试,除非你的思路非常的完美,否则一般情况下在将所有的测试用例都调对的情况下还会有一些测试点无法通过,而这时候测试用例已经没办法帮你了,你就需要根据测试点的提示信息自己去写一个测试用例进行调试,这一步有时候可能比你写代码还要耗费时间。
3.难点:
这两次大作业的主要难点是第八次大作业的电位输出以及电流计算,因为电位如果是并联电路的一条路断了但另一条路没有断那么断了的那条路末端的电压很可能会受到别的路的电流的影响,另外电流计算主要是开关那些没有电阻的设备没有办法直接根据公式来计算电流,需要看整条路的电流情况,这样的话代码逻辑就会相对比较麻烦。还有的难点就是测试点的调试,因为这两次大作业的测试用例太少了,如果设计不是特别好,哪怕样例全队可能也就才拿六十分左右,需要自己去设计一些测试用例来进行调试,而在不知道具体要求的情况下编写测试用例本来就难。
二.设计与分析
1.家居强电电路模拟程序-3
针对题目内容,我设计了十六个类,分别是:
(1)Device类:总的电路设备类。
(2)ControlDevice类:Device类的子类,控制设备类,是开关,分档调速器等能够控制电路的设备的父类。
(3)Switch类:开关类,能够控制电路的开闭。
(4)GradeGovernor类:分档调速器类,能够控制通过它的电压大小。
(5)MutexSwitch类:互斥开关类,相当于一个并联电路,开关开向哪边哪边就通,另一边则断开。
(6)ContinuousGovernor类:连续调速器类,能够控制通过它的电压大小。
(7)ControlledDevice类:受控设备类,主要是灯,风扇等受电路控制的设备的父类。
(8)IncandescentLamp类:白炽灯类,根据两端电压的不同,亮度不同。
(9)FluorescentLamp类:日光灯类,根据两端电压的不同,亮度不同。
(10)CeilingFan类:吊扇类,根据两端电压的不同,转速不同。
(11)StandFan类:落地扇类,根据两端电压的不同,转速不同。
(12)Curtain类:受控窗帘类,根据电路中所有灯的总亮度不同,打开程度不同。
(13)Input类:输入读取类,能够将用户的输入信息读取,并根据题目要求将需要的内容存储下来。
(14)SeriesCircuit类:串联电路类,主要是对串联电路的电路情况进行分析,并更新电路中设备的状态。
(15)MultipleCircuit类:并联电路类,主要是对并联电路的电路情况进行分析,并更新电路中设备的状态。
(16)OutPut类:输出类,将电路中设备的状态信息输出。
对应类图如下:
对应时序图如下:
因为互斥开关的出现所以在Input类中增加了设备端口的读取和存储,因为一个互斥开关有两个连接端口,不同的端口连接电阻不同所以需要根据互斥开关的端口来对电阻进行判断,同时在OutPut类中还增加了将所有的灯设备的亮度进行累加再根据累加结果对受控窗帘进行更新的操作,因为受控窗帘独特的控制机制,必须要所有设备都更新完状态之后才能进行更新,所以直接在输出的前一步进行更新,以确保所有设备已经更新完毕。
2.家居强电电路模拟程序-4
针对题目内容,我设计了十七个类,分别是:
(1)Device类:总的电路设备类。
(2)ControlDevice类:Device类的子类,控制设备类,是开关,分档调速器等能够控制电路的设备的父类。
(3)Switch类:开关类,能够控制电路的开闭。
(4)GradeGovernor类:分档调速器类,能够控制通过它的电压大小。
(5)MutexSwitch类:互斥开关类,相当于一个并联电路,开关开向哪边哪边就通,另一边则断开。
(6)ContinuousGovernor类:连续调速器类,能够控制通过它的电压大小。
(7)ControlledDevice类:受控设备类,主要是灯,风扇等受电路控制的设备的父类。
(8)IncandescentLamp类:白炽灯类,根据两端电压的不同,亮度不同。
(9)FluorescentLamp类:日光灯类,根据两端电压的不同,亮度不同。
(10)CeilingFan类:吊扇类,根据两端电压的不同,转速不同。
(11)StandFan类:落地扇类,根据两端电压的不同,转速不同。
(12)Curtain类:受控窗帘类,根据电路中所有灯的总亮度不同,打开程度不同。
(13)Input类:输入读取类,能够将用户的输入信息读取,并根据题目要求将需要的内容存储下来。
(14)SeriesCircuit类:串联电路类,主要是对串联电路的电路情况进行分析,并更新电路中设备的状态。
(15)MultipleCircuit类:并联电路类,主要是对并联电路的电路情况进行分析,并更新电路中设备的状态。
(16)OutPut类:输出类,将电路中设备的状态信息输出。
(17)Diode类:二极管类,正向连接导通电路,反向连接截止电路。
对应类图如下:
对应时序图如下:
因为这次大作业增加了设备两端电位的输出以及电流的判断,所以在SeriesCircuit类中增加了电流计算,以及开关等没有电阻的设备的通过电流的计算的函数,以及并联电路断开的那条路是否会受到其他没有断开的路的电流的影响的判断。
三. 采坑心得
1.在家居强电电路模拟程序-3中主要遇到的问题就是不管输入是什么互斥开关那里有时候正常有时候会直接全部断开,后面查看代码发现我在读取互斥开关的端口的时候只会读取一边,有时候直接就只读取了一个一端口,所以根本无法判断互斥开关的状态,后面在增加了一个判断之后成功解决了这个问题。
对应判断代码如下:
点击查看代码
else if (name.startsWith("H")){
int port= Integer.parseInt(parts2[i].split(" ")[1].split("-")[1].trim());
if(port==1){
port=Integer.parseInt(parts2[i+1].split(" ")[0].split("-")[1].trim());
mutex.put(name,port);
devices.add(new MutexSwitch(name));
}
else {
mutex.put(name,port);
devices.add(new MutexSwitch(name));
}
对应去重代码如下:
removeDuplicates(mutexSwitches);
3.在家居强电电路模拟程序-4中每一次互斥开关的断开那个端口的电位值一直是错误的,后面经过调试发现原来是在处理过程中,连通的那一端和断开的那一端被分成了两个名字相同的互斥开关,所以它们对应更新的端口也不同,而另外的端口则是一直无法更新,最后我增加一个将它们两个的数据进行交换的功能,让互斥开关可以更新所有的端口电位。
对应数据交换代码如下:
点击查看代码
for(int i=0;i<mutexSwitches.size()-1;i++){
if(mutexSwitches.get(i).getName().equals(mutexSwitches.get(i+1).getName())){
if(((MutexSwitch)mutexSwitches.get(i)).isLink()){
((MutexSwitch)mutexSwitches.get(i)).setBlockVoltage(((MutexSwitch)mutexSwitches.get(i+1)).getBlockVoltage());
((MutexSwitch)mutexSwitches.get(i+1)).setInputVoltage(((MutexSwitch)mutexSwitches.get(i)).getInputVoltage());
((MutexSwitch)mutexSwitches.get(i+1)).setOutputVoltage(((MutexSwitch)mutexSwitches.get(i)).getOutputVoltage());
}
else {
((MutexSwitch)mutexSwitches.get(i+1)).setBlockVoltage(((MutexSwitch)mutexSwitches.get(i)).getBlockVoltage());
((MutexSwitch)mutexSwitches.get(i)).setInputVoltage(((MutexSwitch)mutexSwitches.get(i+1)).getInputVoltage());
((MutexSwitch)mutexSwitches.get(i)).setOutputVoltage(((MutexSwitch)mutexSwitches.get(i+1)).getOutputVoltage());
}
}
}
-
避免重复计算:在当前的设计中,尤其是在串联电路和并联电路的处理中,每次设备状态的更新可能涉及到大量的计算和遍历。为避免重复计算,可以考虑为每个设备增加状态缓存。例如,每个设备可以缓存其电流、电压等重要参数,并通过标志位标记设备状态是否已经更新。在电路状态更新时,只有当设备状态发生变化时,才重新计算电流或电压。这样可以减少不必要的重复计算,提高程序的性能。
-
抽象电路类型和设备类型:在处理不同类型电路(如串联、并联)时,可以进一步抽象出电路类型和设备类型。比如,设计一个Circuit接口,定义基本的电路操作方法(如更新电路状态、计算电流等)。然后根据电路类型(串联、并联等)实现不同的电路类。这样能够实现电路的可扩展性,当需要加入新的电路类型时,只需扩展接口的实现即可。
-
优化排序算法:bubbleSort 排序算法比较低效,当设备数量增多时,性能会急剧下降。可以将其替换为更高效的排序算法,能够提高排序操作的性能。
-
减少不必要的遍历:在updateInputVoltage(),每次更新设备状态时都要遍历所有设备。可以想办法看看能不能减少遍历。
五. 总结
这两次大作业总体来说还是非常具有挑战性的,尤其是在增加了互斥开关同时还要显示各个端口的电位的时候,需要考虑的东西非常多,一不小心就会出错。不过这两次大作业也是非常大程度的训练了我的代码调试能力,因为这两次大作业涉及了非常多的计算,以及状态的更新如果错了,很难通过代码看出问题,需要一步步调试与实践计算出来的值进行对比最后将错误点锁定。而且这两次大作业让我对类的使用有有了更深层次的理解,让我可以更加熟练的使用抽象类来解决问题。不过我还是希望以后像最后面几题难度这么大的题可以多给一些测试用例,因为有一些点实在是太难想到了,而且自己编写测试用例太难也太耗费时间了,更何况后面还要进行调试,那花费的时间就更多了,有时候别人也没有全对所以也根本不知道自己的测试用例到底对不对。
六. 学期总结
本学期通过学习课程以及PTA练习,我收获了很多新的知识,尤其是面向对象编程原则以及类的使用更是记忆深刻,前者不用提,因为从第一节课开始到学期结束每一次课,每一次练习都在提醒要面向对象编程,后者则是在PTA练习中频繁使用,不仅使用方便而且还可以帮助我们简化很多的问题,尤其是抽象类,如果使用合理可以帮我们减轻很多的工作量。另外提供这学期的PTA练习,我的代码调试能力已经得到了突飞猛进的提升,课程刚开始的时候我对代码调试还不是很熟练,经过多次的练习之后,我已经可以通过调试快速的找出问题所在并将它解决。同时我的题目理解能力以及逻辑设计能力都得到了非常大的提升,尤其是在家居强电电路模拟程序-2中我几乎是一次就过了,几乎后面没有这么调试修改就拿到了一百分。我心里想说的话就是难度大的题目能不能多增加一些测试用例啊,自己编写样例真的好花费时间,哪怕不增加起码测试点的提示要指向性强一些啊,那么笼统,真的很难自己设计测试用例。