一.前言
对于最后两次大作业,我只能说,从第七次大作业到最后一次大作业的难度跨度非常大,虽然是第七次作业的题目量已经很大了,但是最后一次大作业的题量更上一层楼。
由于吸取了之前的教训,我之前有一次一直等到周末还剩两三天的时候才开始写大作业,导致最后几天写大作业的时候非常焦虑,然后我一焦虑就很难发挥出平时的能力,导致最后没有拿到满分,所以这一次我从周二就开始打开第七次题目集开始设计,这一次增加了一个受控窗帘,还增加了一种情况,就是多种并联电路可以串联在一起,一开始我还以为这个受控窗帘就只是一个简单的受控设备,结果发现它的逻辑并非我想象中的那么简单,我感觉这一次考察的知识点主要还是继承与多态,当题目新增加一种别具一格的受控设备时,考察你如何将他某些方法实现多态,这一次的难度我还可以接受,因为我花了两三天的时间全在思考和设计这个题目,
对于第八次题目集我只能说,它的难度超出了我的想象,至于我为什么会这么说,下面我会详细讲解。我认为这一次考察的主要是你的思维逻辑,如果你想拿满分那我可以告诉你,没门!因为我们这一次没一个满分的,当然这也有时间比较紧迫的原因,因为最后一次大作业已经临近期末考试的时间了,所以大家应该也不太愿意花那么多时间在最后一次作业上,可以理解,但他的难度不容小看,他这一次考察的东西我认为就是看你是否能尽量多的考虑到多种情况,你考虑的情况越多,就能拿越多的分,这一次大作业我的代码量已经达到一千四百多行了,所以他的难度可想而知。
二.设计与分析、踩坑心得、改进建议
一:家居强电电路模拟程序-3:
设计与分析:
这一题是建立在家居强电电路模拟程序-2上的,这一次增加了一个受控窗帘,然后也增加了多并联电路串联的情况。
由于存在单条电路含有多个并联电路的情况,所以在串联电路类中增加一个存放并联电路的列表的属性,然后增加了一个受控窗帘的受控设备。
由于这一次基础的设计框架没有改动,所以这里就不用具体的类图来表示了,可以参考我上一次的具体设计。
这里我只讲解有改动的类及他们的方法。
1.受控窗帘Controlled_curtain:
属性:
窗帘打开比例proportion(String类型)
输入获取的室内总光强all_brightness(double类型)
方法:
方法一:
获取室内总光强setAll_brightness(光强)
这里不展示详细代码。
方法二:
更新设备状态updateDevice()
这里展示详细代码:
点击查看代码
public void updateDevice(double inputVoltage){
if(inputVoltage>=50){
if(this.all_brightness>=400){
this.proportion = "0%";
} else if (this.all_brightness>=300) {
this.proportion = "20%";
} else if (this.all_brightness>=200) {
this.proportion = "40%";
} else if (this.all_brightness>=100) {
this.proportion = "60%";
} else if (this.all_brightness>=50) {
this.proportion = "80%";
}else {
this.proportion = "100%";
}
}
}
2.复合电路类Compound_Circuit:
属性:(这里只详细介绍该类新增的属性和方法,下面介绍其他类时相同)
并联电路列表multiple_circuitList
方法:
判断复合电路是否闭合if_allSwitch_closed
这里不仅要考虑开关、互斥开关和正常的串联电路,还要判断多个并联电路是否闭合。
这里展示详细代码:
点击查看代码
//判断复合电路中除包含的并联电路和串联电路之外的所有开关是否全部关闭
public boolean if_allSwitch_closed() {
List<Switch> K_list = new ArrayList<>();//复合电路存放开关列表
List<Exclusive_switch> H_list = new ArrayList<>();//复合电路存放互斥开关列表
boolean temp = true;
for (Device device : this.devices_parts.values()) {
if (device.getId().startsWith("K")) {
K_list.add((Switch) device);
}
if (device.getId().startsWith("H")) {
H_list.add((Exclusive_switch) device);
}
}
for (Switch k_switch : K_list) {
if (k_switch.getStatus().equals("turned on")) {
temp = false;
break;
}
}
if (!this.E_subscript.isEmpty()){
for (Exclusive_switch h_switch : H_list) {
if ((h_switch.getStatus().equals("turned on") && this.E_subscript.get(h_switch.getId()) == 2) ||
h_switch.getStatus().equals("closed") && this.E_subscript.get(h_switch.getId()) == 3) {
temp = false;
break;
}
}
}
for (Multiple_Circuit circuit:this.multiple_circuitList.values()) {
if(circuit.if_allSwitch_open()){
temp = false;
}
}
for (Series_Circuit circuit:this.series_CircuitList.values()) {
if(!circuit.if_allSwitch_closed()){
temp = false;
}
}
return temp;
}
3.串联电路类Series_Circuit:
属性:(这里只详细介绍该类特有的属性与方法,下面介绍其他类时相同)
互斥开关的输出引脚序号状态E_subscript(Map类型)
(这个属性是用来保存互斥开关的输入或输出引脚在该条串联电路的序号)
方法:
方法一:判断该开关的输出引脚的编号为2或judge_pin(字符串)
这里展示详细代码:
点击查看代码
//当存在互斥开关,判断该开关的输出引脚的编号为2或3
public void judge_pin(String str){
if(str.split(" ")[0].charAt(0)=='H'&&str.split(" ")[0].charAt(3)!='1') {
if (str.split(" ")[0].split("-")[1].equals("2"))
this.E_subscript.put(str.split(" ")[0].split("-")[0],2);
else if (str.split(" ")[0].split("-")[1].equals("3")){
this.E_subscript.put(str.split(" ")[0].split("-")[0],3);
}
}else if(str.split(" ")[1].charAt(0)=='H'&&str.split(" ")[1].charAt(3)!='1'){
if (str.split(" ")[1].split("-")[1].equals("2"))
this.E_subscript.put(str.split(" ")[1].split("-")[0],2);
else if (str.split(" ")[1].split("-")[1].equals("3")){
this.E_subscript.put(str.split(" ")[1].split("-")[0],3);
}
}
}
以上便是有变动的类或方法的详细设计。
类图设计:这一次的设计与上一次几乎一致,就不再详细介绍了。
踩坑心得
因为这一次的设计我花了比较多的时间去思考,所以考虑到底情况比较多。
第一次提交就已经得到了83分,但这里还是有几个测试点未通过:
这里可以看到还是有6个测试点未通过。
后来我仔细检查代码发现,我在串联电路类的获取设备的方法中忘记了使用判断互斥开关引脚的方法,如下图所示:
可以看到我这里没有引用方法judge_pin()这个方法,那么我就没办法知道互斥开关在这条电路上的输出引脚是2还是3,加上这个方法后,便通过了最上面两个测试点:
这里还剩下4个测试点,对于这几个测试点,我思考了蛮久,我以为可能是我在多并联电路那里的设计有所欠缺,或者还有我没有考虑到底情况,但我尝试了很多种设计,都没有成功拿下这几个测试点,后来我向同学咨询,才发现这一次的输出不是按照以往的方式了,之前是先按照电器种类再按照同一种类的序号数值来排序,但这一次是先按照电器种类,再按照序号字符来排序,也就是说,需要直接对序号字符来排序,而不是把序号字符改为整数型数值来排序,变动如下图所示:
再一次提交,发现只剩下最后一个测试点了:
对于最后一个测试点,其实我也思考了很久,而且问同学,同学也无能为力,这曾一度让我想放弃这个测试点,但就在某一次java课上,我无意间做了一个小改动:
这里可以看到,我将judge_pin()这个方法移除下面的if判断语句,结果就满分了,后来我仔细思考了一下,发现其实是因为我忽略了一种情况,当互斥开关放在电路的末尾时,如果按照我修改之前的方法来运行,就不会执行judge_pin()这个方法了,从而忽略了这种情况,修改完后发现满分了:
改进建议:
我发现我这一次有一个一直重复的问题,就是我老是忘了我之前写的方法是干嘛用的,导致我浪费了很多时间去重新理解我写的方法有什么作用,究其原因就是我没有给必要的方法一定的注释,人的记忆都是有限的,所以这一次需要改进的地方就是需要在重要的方法后完善注释部分,这样下一次看到这个方法就可以短时间内理解他的目的与作用,而不用重新从头看到尾。
一:家居强电电路模拟程序-4:
设计与分析:
这一次的设计是建立在家居强电电路模拟程序-3的基础上,这次的题目增加了一个控制设备二极管,而且这一次的题目增加了一种新的情况,就是并联电路中还会出现并联电路,除此之外,这一次的大作业要求计算所有设备的每个引脚的电压值。
所以这一次的难度大大提升。
由于这一次作业的设计是在模拟程序-3的基础上,这里只详细介绍相对于上一次作业改变了的或者新添加的设计的地方:
1.设备类Device(抽象类)
属性(这里只展示新添加的属性):
最大限定电流max_current(double类型)
设备所获电流electricity(double类型)
(由于这一次的题目要求判断经过设备的电路是否超过最大允许通过的电流值,所以这里增加了这两个属性)
引脚是否正接标志if_pConnection(boolean类型)
(这个属性是为了判断每个设备是正接还是反接,因为每个设备的引脚有前后之分)
方法(这里只展示新添加的方法):
无新增方法。
2.二极管类Diode
属性:无特殊属性。
方法:获取设备状态getStatus()
这里展示详细代码:
点击查看代码
@Override
public String getStatus() {
String status = this.if_pConnection ? "conduction " : "cutoff ";
status += (int) this.pin_1 + "-" + (int) this.pin_2;
if (this.electricity > this.max_current) {
status += " exceeding current limit error";
}
return status;
}
3.串联电路类Series_Circuit
属性:无新增属性
方法:(这里只详细讲解新增或改动的方法)
方法一:判断设备是否正反接judge_connect()
(该方法的目的是为了将每一个设备的引脚按接入的方向来确定)
这里展示详细代码:
点击查看代码
//判断正常设备是否反接
public void judge_connect(){
for (String part:this.Connections) {
String str = part.split(" ")[1];
if(!str.equals("OUT")){
String id = str.split("-")[0];
if(!str.split("-")[1].equals("1")&&!str.split("-")[1].equals("IN")){
this.devices_parts.get(id).reversal_connect();
}
}
}
}
方法二:判断串联电路是否闭合if_allSwitch_closed()
(这个方法新增加了对二极管和并联电路是否闭合的判断)
这里展示详细代码:
点击查看代码
//判断串联电路中的所有开关是否全部关闭
public boolean if_allSwitch_closed(){
List<Switch> K_list = new ArrayList<>();//串联电路存放开关列表
List<Exclusive_switch> H_list = new ArrayList<>();//串联电路存放互斥开关列表
List<Diode> D_list = new ArrayList<>();//串联电路存放二极管列表
boolean temp = true;
for (Device device:this.devices_parts.values()) {
if(device.getId().startsWith("K") && device instanceof Switch){
K_list.add((Switch)device);
}
if(device.getId().startsWith("H") && device instanceof Exclusive_switch){
H_list.add((Exclusive_switch)device);
}
if (device.getId().startsWith("P") && device instanceof Diode) {
D_list.add((Diode) device);
}
}
for (Switch k_switch:K_list) {
if(!k_switch.get_State()){
temp=false;
break;
}
}
if(!this.E_subscript.isEmpty()) {
for (Exclusive_switch h_switch : H_list) {
if ((!h_switch.get_State() && this.E_subscript.get(h_switch.getId()) == 2) ||
h_switch.get_State() && this.E_subscript.get(h_switch.getId()) == 3) {
temp = false;
break;
}
}
}
for (Diode diode:D_list) {
if (!diode.get_direction_connect()) {
temp = false;
break;
}
}
for (Multiple_Circuit circuit:this.multiple_circuitList.values()) {
if(circuit.if_allSwitch_open()){
temp = false;
}
}
return temp;
}
方法三:串联电路分配压差trans_voltage()
(由于需要计算每个引脚的压值,所以这个方法需要重新设计,大概思路就是,先计算这条电路中每个设备分配的压差,然后计算电路的电流,第一个设备的输入引脚压值等于该电路的输入电压值,后一个设备的输入引脚压值等于前一个设备的输出引脚压值)
由于代码量有点大,所以这里不详细展示了。
方法四:新的传输电压规则trans_pin_new(输入压值,输出压值)
(这个方法区别于当整条电路连通时的情况,因为当电路断开后,可能会存在前一个设备的引脚压值低于后一个设备的引脚压值的情况,这里就提供这样一个大概的思路吧)
这里就不详细展示代码了,因为代码量也很大。
8.处理系统类Center_System
属性:无新增的属性。
方法:
方法一:输入处理input()
(这里有一些改动,因为要想更新受控窗帘的状态值,那就必须提前获取总电路中所有灯的亮度,但是在传输电压的方法中没办法提前知晓所有的灯的亮度,因为存在灯出现在受控窗帘之后的情况,那么这样的话,就必须先不更新受控窗帘的状态值,等到所有设备传输完电压后,再来获取所有灯的亮度,最后再更新受控窗帘的状态值)
这里展示详细代码:
点击查看代码
this.compound_circuit.trans_voltage();
double all_brightness = 0;
for (Device device:this.compound_circuit.get_Devices().values()) {
if(device instanceof Lamp){
all_brightness += ((Lamp) device).getBrightness();
}
}
for (Device device:this.compound_circuit.get_Devices().values()) {
if(device.getId().charAt(0)=='S'){
Controlled_curtain curtain = (Controlled_curtain) device;
curtain.setAll_brightness(all_brightness);
curtain.updateDevice();
}
}
类图设计:这次的类图设计较为复杂,图片无法清晰的显示,这里就不详细展示了。
踩坑心得
这一次的难度非常大,我第一次提交只得了46分:
这一次我主要是调试代码,将题目已给的测试样例给通过了,但过了一小部分的测试点,然后我突然想到老师上课提到过的一种情况,刚刚我也在上面的描述中讲解到,就是我需要去考虑一种情况,在一条串联电路中,前一个设备的引脚电压值有可能低于后一个设备的引脚电压值,这是因为当串联电路断开时,不会有电流通过,那么每个设备的引脚就不会完全取决与前一个设备的输出引脚值,比如有三个断开的开关接在一条串联电路上,这条电路的输入和输出引脚值分为是220V和100V,那么你会发现,中间这个开关的两个引脚值都为0,而最后一个开关的输出引脚却为100V,那么这样就是我所说的一种情况,当然,除了这种还有更复杂的情况需要我们去思考,我这里只简单讨论这一种情况,因为我也只拿了61分。
所以将这种情况考虑进去后,我又通过了一些测试点:
到这里已经是我的极限了,因为我已经没什么时间再来考虑更多的情况了,我要开始复习期末考试了,所以我这一次能及格我已经很满足了。
改进建议:
我发现我这一次的设计中,有某些方法的代码量非常大,这其实是不符合java编程正常的设计规范的所以我觉得这一点我需要改进一下,我可以将一个方法所需要实现的功能拆分成好几个不同的小方法,然后直接在主要方法里调用这些方法从而减少主方法中代码的冗余程度。
总结:
从最后的这两次大作业中,我觉得我最大的收获就是锻炼了自己的思维设计能力,这两次大作业我都用草稿纸将自己考虑到的所有情况全都通过画图的形式直观的展示出来,我发现通过这样的方式我能够更清晰的扩展自己的思维,考虑到更加复杂的情况,除此之外,我觉得这两次的大作业也提升了我的编程能力,在之前的学习生涯中,除了期末的课程设计外,我很少进行这么大代码量的编程设计,最后这两次的代码量已经到了一千多行,这放在以前我想都不敢想我做个pta作业要敲这么多代码,但是我现在已经适应了这种大的代码量的编程环境。
学期总结:
其实当我第一次看到这学期的这么课程时,我是非常兴奋的,因为之前老是在短视频上刷到java语言,所以我就很好奇这个语言和我之前学过的c与c++有什么区别,所以这门课程我是带着一种好奇的探索心理去学习的,而且这门课还配有相应的pta大作业,所以对于每一次的大作业我都非常感兴趣,每一次一到大作业开放的时间我就会立马点开来,然后分析题目看看这一次大作业新增了什么内容,所以我觉得通过这个学期的java课程,我已经学习到了很多关于java的知识,我也熟悉了java语言的编程过程,虽然感觉这门课好像对于我们物联网工程这个专业没啥用,因为在大多数人看来,java应该是专属于软件工程专业的同学的课程,但是通过这学期的学习,我觉得让我充分理解并掌握了java的语法相关知识,至少以后别人问我会什么编程语言,我可以很自信的说出java,哈哈,当然语法终归还是语法,所有的编程语言最主要还是为了开发具体的工程项目,所以如果后面有时间我也会去找一个用java语言来开发的项目做一做。