NCHU-OOP课程与PTA七到八周作业总结
NCHU-OOP课程与PTA七到八周作业总结
引言
关于这两次的题目集:
这两周的题目并没有用到更多新的知识,但是在综合运用上的难度却大大提升了,更需要对于程序逻辑和各种特殊情处理上清晰逻辑,更需要一个更好的结构;
这两次的题目集的难度都明显上来了很多,是真正考验设计和修改能力的时候;但很可惜,尽管我在最后一次题目集的时候画了很多时间去修改和完善,但是在最后一次结束前,还是只获得了72分的成绩,非常遗憾,但也无可奈何,还是结构设计和程序逻辑上存在各种问题导致的,归根结底都是自己没有实力啊;
第七次题目集只有一道题目,新增互斥开关,窗帘等元件;互斥开关的处理个人认为是很难的;
7-1家居强电电路模拟程序-3
第八次题目集只有一道题目,继续迭代,新增引脚输入判断,各种电压的输出;尽管已经花了很多时间,但是还是没实力拿满分:
7-1 家居强电电路模拟程序-4
课程内容总结:
1.继续学习了解了部分设计模式,这里仅简单对进行练习尝试的策略模式总结下;
目的:将每一个算法封装起来,并使它们可以相互替换,让算法的变化独立于使用算法的客户,减少代码间的耦合,增加系统的灵活性和可扩展性。是实现对不同对象采取不同策略,遵循开闭原则的重要方式;
主要实现:依赖于以下三个类;
(1) 策略接口(Strategy Interface):定义所有支持的算法的公共接口。
(2)具体策略类(Concrete Strategy Classes):实现策略接口的各个具体算法类。
(3) 上下文环境(Context):持有一个策略接口引用的类,负责根据需要调用具体的策略算法。
参考类图:
具体实现:
上下文根据请求选择合适的策略对象执行算法,而无需了解具体策略是如何实现的。
当需要改变行为时,只需要创建一个新的具体策略类并设置到上下文中即可,无需修改原有代码。
2.Java异常处理机制
(1)异常分类:
检查性异常(Checked Exceptions):如IOException,编译时要求处理。
运行时异常(Unchecked Exceptions):如NullPointerException,编译器不强制处理。
(2)异常处理:
try:包围可能抛出异常的代码。
catch:捕获并处理特定异常,可有多个。
finally:无论是否发生异常都会执行的代码块,用于资源清理。
throw:主动抛出异常。
throws:声明方法可能抛出的异常类型。
(3)基本结构:
java try { // 可能抛出异常的代码 } catch (异常类型 异常变量) { // 异常处理代码 } finally { // 清理资源代码 }
(4)此外还可以自定义异常,通过继承Exception或其子类创建,增强错误描述的针对性。
3.JavaFX的学习和使用
见实验五;
参考链接:
JavaFX常用控件_javafx 组件大全-CSDN博客
史上最直观的JavaFx布局讲解(超多图)BorderPane、StackPane、GridPane、AnchorPane等_tabepane布局和哪些布局搭配使用-CSDN博客
PTA-oop-7
家居强电电路模拟程序-3
题目:
智能家居是在当下家庭中越来越流行的一种配置方案,它通过物联网技术将家中的各种设备(如音视频设备、照明系统、窗帘控制、空调控制、安防系统、数字影院系统、影音服务器、影柜系统、网络家电等)连接到一起,提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。与普通家居相比,智能家居不仅具有传统的居住功能,兼备建筑、网络通信、信息家电、设备自动化,提供全方位的信息交互功能。请根据如下要去设计一个智能家居强电电路模拟系统。以下题目介绍中加粗的部分为本次迭代在“家居强电电路模拟程序-2”的基础上增加的功能要求。
1、控制设备
本题模拟的控制设备包括:开关、分档调速器、连续调速器、互斥开关。
开关:包括0和1两种状态。
开关有两个引脚,任意一个引脚都可以是输入引脚(接往电源端),而另一个则是输出引脚(接网接地端)。开关状态为0时,无论输入电位是多少,输出引脚电位为0。当开关状态为1时,输出引脚电位等于输入电位。
互斥开关:
互斥开关有3个引脚:1个是汇总引脚,另两个是分支引脚。
开关电路示意图如图1所示,左边是汇总引脚,编号为1;右边两个是分支引脚,右上的输出引脚为2,右下输出引脚为3。图中1、2、3引脚均可以是输入引脚,当1为输入引脚时,2、3引脚为输出引脚;1为输出引脚时,2、3引脚为输入引脚。
互斥开关只有两种状态:开关接往上面的2号引脚、接往下面的3号引脚。开关每次只能接通其中一个分支引脚,而另一个分支引脚处于断开状态。
互斥开关的默认状态为1、2引脚接通,1、3引脚断开。
图1中所示的互斥开关可以反过来接入电路,即汇总引脚接往接地端,两个分支引脚接往电源端。
image.png
图1 互斥开关
为避免短路,互斥开关设置了限流电阻,12引脚之间默认电阻为5,13引脚之间默认电阻为10。
分档调速器
按档位调整,常见的有3档、4档、5档调速器,档位值从0档-2(3/4)档变化。本次迭代模拟4档调速器,每个档位的输出电位分别为0、0.3、0.6、0.9倍的输入电压。
连续调速器
没有固定档位,按位置比例得到档位参数,数值范围在[0.00-1.00]之间,含两位小数。输出电位为档位参数乘以输入电压。
所有调速器都有两个引脚,一个固定的输入(引脚编号为1)、一个输出引脚(引脚编号为2)。当输入电位为0时,输出引脚输出的电位固定为0,不受各类开关调节的影响。
开关、调速器的初始状态/档位为0。
调速器的输入引脚编号为1,输出引脚编号为2。
除互斥开关外,其他控制设备的电阻为 0。
2、受控设备
本题模拟的受控设备包括:灯、风扇。两种设备都有两根引脚,通过两根引脚电压的电压差驱动设备工作。
灯有两种工作状态:亮、灭。在亮的状态下,有的灯会因引脚电位差的不同亮度会有区别。
风扇在接电后有两种工作状态:停止、转动。风扇的转速会因引脚间电位差的不同而有区别。
本次迭代模拟两种灯具。
白炽灯:
亮度在0~200lux(流明)之间。
电位差为0-9V时亮度为0,其他电位差按比例,电位差10V对应50ux,220V对应200lux,其他电位差与对应亮度值成正比。白炽灯超过220V。
日光灯:
亮度为180lux。
只有两种状态,电位差为0时,亮度为0,电位差不为0,亮度为180。
本次迭代模拟两种风扇。
吊扇:
工作电压区间为80V-150V,对应转速区间为80-360转/分钟。80V对应转速为80转/分钟,150V对应转速为360转/分钟,超过150V转速为360转/分钟(本次迭代暂不考虑电压超标的异常情况)。其他电压值与转速成正比,输入输出电位差小于80V时转速为0。
落地扇:
工作电压区间为 80V-150V,对应转速区间为 80-360 转/分钟;[80V,100V) 对应转速为 80 转/分钟;[100,120)V 对应转速为 160 转/分钟;[120,140)V 对应转速为 260 转/分钟;大于等于 140V 转速 为 360 转/分钟(本次迭代暂不考虑电压超标的异常情况)。
本次迭代模拟一种受控窗帘:
受控窗帘的电路符号为S,其最低工作电压为50V,电压达到或超过50V,窗帘即可正常工作,不考虑室外光照强度和室内空间大小等因素,窗帘受室内灯光的光照强度控制。
当电路中所有灯光的光照强度总和在[0,50)lux范围内,窗帘全开;
在[50,100)lux范围内,窗帘打开比例为0.8;
在[100,200)lux范围内,窗帘打开比例为0.6;
在[200,300)lux范围内,窗帘打开比例为0.4;
在[300,400)lux范围内,窗帘打开比例为0.2;
在400lux及以上范围内,窗帘关闭。
当电压低于50V,窗帘不工作,默认为全开状态。
如果电路中没有灯或者灯全部关闭,光照强度为0,窗帘处于全开状态。
受控设备电阻:白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落地扇的电阻为 20,窗帘电阻为15。
3、输入信息
1)输入设备信息
分别用设备标识符K、F、L、B、R、D、A、H、S分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇、互斥开关、受控窗帘。
设备标识用标识符+编号表示,如K1、F3、L2等。
引脚格式:设备标识-引脚编号,例如:K1-1标识编号为1的开关的输入引脚。
开关、分档调速器、连续调速器的输入引脚编号为1,输出引脚编号为2。
受控设备的两个引脚编号分别为1、2。
互斥开关的引脚编号已经在互斥开关的介绍部分说明。
约束条件:
不同设备的编号可以相同。
同种设备的编号可以不连续。
设备信息不单独输入,包含在连接信息中。
2)输入连接信息
一条连接信息占一行,用[]表示一组连接在一起的设备引脚,引脚与引脚之间用英文空格" "分隔。
格式:"["+引脚号+" "+引脚号+"]"
例如:[K1-1 K3-2]表示K1的1引脚,K3的2引脚连接在一起。
约束条件:
不考虑调速器串联到其他调速器的情况。
考虑各类设备的并联接入。例如,K1 的输出接到 L2 的输入,L2 的输出再接其他设备属于串联接线。K1 的输出接到 L2 的输出,同时 K1 的输入接到 L2 的输入,这种情况属于并联。
本次迭代的连接信息不单独输入,包含在线路信息中。
3)输入控制设备调节信息
开关、互斥开关调节信息格式:
#+设备标识K+设备编号,例如:#K2,代表切换K2开关的状态。
#+设备标识H+设备编号,例如:#H2,代表切换H2互斥开关的状态。
分档调速器的调节信息格式:
#+设备标识F+设备编号+"+" 代表加一档,例如:#F3+,代表F3输出加一档。
#+设备标识F+设备编号+"-" 代表减一档,例如:#F1-,代表F1输出减一档。
连续调速器的调节信息格式:
#+设备标识L+设备编号+":" +数值 代表将连续调速器的档位设置到对应数值,例如:#L3:0.6,代表L3输出档位参数0.6。
4)电源接地标识:
VCC,电压220V,GND,电压0V。没有接线的引脚默认接地,电压为0V。
5)输入串联电路信息
一条串联电路占一行,串联电路由按从靠电源端到接地端顺序依次输入的 n 个连接 信息组成,连接信息之间用英文空格" "分隔。
串联电路信息格式:
"#T"+电路编号+":"+连接信息+" "+连接信息+...+" "+连接信息
例如:#T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT] 一个串联电路的第一个引脚是 IN,代表起始端,靠电源。最后一个引脚是 OUT,代表结尾端, 靠接地。
约束条件:
不同的串联电路信息编号不同。
输入的最后一条电路信息必定是总电路信息,总电路信息的起始引脚是 VCC,结束引脚是 GND。
连接信息中的引脚可能是一条串联或并联电路的 IN 或者 OUT。例如:
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT OUT]
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT M2-IN] [M2-OUT OUT]
6)输入并联电路信息
一条并联电路占一行,并联电路由其包含的几条串联电路组成,串联电路标识之间用英文空格" "分隔。
格式:
"#M"+电路编号+":"+”[”+串联电路信息+" "+....+" "+串联电路信息+”]”
例如:#M1:[T1 T2 T3]
该例声明了一个并联电路,由 T1、T2、T3 三条串联电路并联而成,三条串联电路的 IN 短 接在一起构成 M1 的 IN,三条串联电路的 OUT 短接在一起构成 M1 的 OUT。
约束条件:
本次迭代不考虑并联电路中包含并联电路的情况。
本题不考虑输入电压或电压差超过220V的情况。
输入信息以end为结束标志,忽略end之后的输入信息。
本题中的并联信息所包含的串联电路的信息都在并联信息之前输入,不考虑乱序输入的情况。
只要不因短路而造成无穷大的电流烧坏电路(如电路中的部分短接),都是合理情况,在测试点的考虑范围之内。会造成无穷大的电流的短路本次迭代不考虑。
本次迭代考虑多个并联电路串联在一起的情况。
本题考虑一条串联电路中包含其他串联电路的情况。例如:
#T3:[VCC K1-1] [K1-2 T2-IN] [T2-OUT K2-1] [K2-2 T1-IN] [T1-OUT GND]
本例中T1\T2两条串联电路T3的一个部分,本题考虑这种类型的输入。
4、输出信息:
按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、互斥开关、受控窗帘的顺序依次输出所有设备的状态或参数。每个设备一行。同类设备按编号顺序从小到大输出。
输出格式:
@设备标识+设备编号+":" +设备参数值(控制开关的档位或状态、灯的亮度、风扇的转速,只输出值,不输出单位)
连续调速器的档位信息保留两位小数,即使小数为0,依然显示两位小数.00。
开关状态为0(打开)时显示turned on,状态为1(合上)时显示closed
如:
@K1:turned on
@B1:190
@L1:0.60
互斥开关显示1、2引脚的接通状态,接通时显示closed,断开时显示turned on。
如:
@H1:turned on
受控窗帘显示窗帘打开的百分比,如:
@S1:80%
5、家居电路模拟系列所有题目的默认规则:
1)当计算电压值等数值的过程中,最终结果出现小数时,用截尾规则去掉小数部分,只保留整数部分。为避免精度的误差,所有有可能出现小数的数值用double类型保存并计算,不要作下转型数据类型转换,例如电压、转速、亮度等,只有在最后输出时再把计算结果按截尾规则,舍弃尾数,保留整数输出。
2)所有连接信息按电路从电源到接地的顺序依次输入,不会出现错位的情况。电源VCC一定是第一个连接的第一项,接地GND一定是最后一个连接的后一项。
3)连接信息如果只包含两个引脚,靠电源端的引脚在前,靠接地端的在后。
4)调速器的输入端只会直连VCC,不会接其他设备。整个电路最多只有连接在电源上的一个调速器,且不包含在并联单路中。
6、家居电路模拟系列1-4题目后续迭代设计:
1)电路结构变化:
迭代1:只有一条线路,所有元件串联
迭代2:线路中包含一个并联电路
迭代3:线路中包含多个串联起来的并联电路
迭代4:并联电路之间可能出现包含关系
电路结构变化示意图见图1。
2)计算方式的变化
迭代1只包含1个受控元件,不用计算电流,之后的电路计算要包含电流、电阻等电路参数。
3)电路元件的变化
每次迭代会增加1-2个新的电路元件。
image.png
图1:电路结构示意图
设计建议:
1、电路设备类:描述所有电路设备的公共特征。
2、受控设备类、控制设备类:对应受控、控制设备
3、串联电路类:一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备
4、并联电路类:继承电路设备类,也看成是一个独立的电路设备
其他类以及类的属性、方法自行设计。
image.png
图2:建议设计类图
输入样例1:
在这里给出一组输入。例如:
#T1:[IN H1-1] [H1-2 D2-1] [D2-2 OUT]
#T2:[IN H1-1] [H1-3 D1-1] [D1-2 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 B2-1] [B2-2 OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M1-IN] [M1-OUT M2-IN] [M2-OUT GND]
#K1
#K2
end
输出样例1:
在这里给出相应的输出。例如:
@K1:closed
@K2:closed
@K3:turned on
@B1:87
@B2:0
@D1:0
@D2:262
@H1:closed
输入样例2:
在这里给出一组输入。例如:
#T1:[IN D2-1] [D2-2 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 B2-1] [B2-2 OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M1-IN] [M1-OUT M2-IN] [M2-OUT GND]
#K1
#K2
end
输出样例2:
在这里给出相应的输出。例如:
@K1:closed
@K2:closed
@K3:turned on
@B1:87
@B2:0
@D1:0
@D2:262
@H1:closed
输入样例3:
在这里给出一组输入。例如:
#T1:[IN K1-1] [K1-2 B2-1] [B2-2 OUT]
#T2:[IN K2-1] [K2-2 R1-1] [R1-2 OUT]
#M1:[T1 T2]
#T3:[VCC K3-1] [K3-2 M1-IN] [M1-OUT S1-1] [S1-2 GND]
#K1
#K2
#K3
end
输出样例3:
在这里给出相应的输出。例如:
@K1:closed
@K2:closed
@K3:closed
@B2:71
@R1:180
@S1:40%
输入样例4:
在这里给出一组输入。例如:
#T1:[IN K2-1] [K2-2 D2-1] [D2-2 OUT]
#T2:[IN K3-1] [K3-2 D1-1] [D1-2 OUT]
#T3:[VCC K1-1] [K1-2 T1-IN] [T1-OUT T2-IN] [T2-OUT GND]
#K1
#K2
#K3
end
输出样例4:
在这里给出相应的输出。例如:
@K1:closed
@K2:closed
@K3:closed
@D1:200
@D2:200
输入样例5:
在这里给出一组输入。例如:
#T3:[VCC B2-1] [B2-2 K1-1] [K1-2 S1-1] [S1-2 H1-1] [H1-2 GND]
#K1
end
输出样例5:
在这里给出相应的输出。例如:
@K1:closed
@B2:95
@H1:closed
@S1:80%
题目分析:
本题在以上基础上新增互斥开关,窗帘等元件;虽然看起来迭代并不是很多,但实际上对于互斥开关的处理还是比较麻烦的;
对于互斥开关,显然需要新增互斥开关类(MutexSwitch)继承自抽象开关类;但是因为抽象开关会同时接入两条串联电路,需要考虑如何保存,我的想法是将同一个开关同时放入两条电路,通过同名引用指向同一个地址的特性修改同一个开关;还是因为这个开关比较特殊,需要记录当前接在哪个接口的状态,可以直接通过现有属性SwitchStatus表示(状态为0时接1-2,为1时接1-3);但是仅仅这样不够,需要保存接入的两条电路名称,新增String[] circuitInfo分别存储2接口,3接口分别在哪个电路中;
对于新增的受控窗帘,虽然是普通电器,但是因为窗帘的打开情况和灯光相关联,需要新建抽象窗帘类(AbstractCurtain),并使窗帘类(Curtain)继承;在总电路中的最后计算总亮度并赋值给窗帘,实现窗帘的更新;
类图设计:
本题类图设计如下:
方法编写:
1.新增两个类,受控窗帘和互斥开关;增加相应的属性并根据元件特性重写renew方法;
//互斥开关
//互斥开关状态为0时接1-2,为1时接1-3
class MutexSwitch extends AbstractSwitch {
private String[] circuitInfo = {"", ""};
public String[] getCircuitInfo() {
return circuitInfo;
}
public void setCircuitInfo(String[] circuitInfo) {
this.circuitInfo = circuitInfo;
}
public void change() {
setSwitchStatus((getSwitchStatus() + 1) % 2);
renew();
}
public void renew() {
setVAfter(getVBefore());
if(this.getSwitchStatus() == 0) {
setR(5);
}
else if(this.getSwitchStatus() == 1) {
setR(10);
}
//更新状态
if(getSwitchStatus() == 0)
setState("closed");
else if(getSwitchStatus() == 1)
setState("turned on");
}
}
//窗帘
class Curtain extends AbstractCurtain{
@Override
public void renew() {
if(getV() >= 50) {
if(getBrightness() >= 50 && getBrightness() < 100) {
setGear(0.8);
}
else if(getBrightness() >= 100 && getBrightness() < 200) {
setGear(0.6);
}
else if(getBrightness() >= 200 && getBrightness() < 300) {
setGear(0.4);
}
else if(getBrightness() >= 300 && getBrightness() < 400) {
setGear(0.2);
}
else if(getBrightness() >= 400){
setGear(0);
}
else {
setGear(1);
}
}
else {
setGear(1);
}
//更新状态
setState(String.format("%.0f%%", 100 * getGear()));
}
}
2.修改输入时正则的判断,使得匹配窗帘的S还有互斥开关的H;
同时对Input类这个负责处理输入的类进行修改;在前几次次迭代中没有牵扯到引脚,所有用电器的输入都和引脚无关,因此前几次Input中都直接按照[]直接将电路元件分割了,也直接去掉了-后面的引脚部分,直接按照每两个将元件放入电路;但是在本次和今后的迭代中,引脚都是很重要的,是分辨互斥开关等是怎么接通的重要凭据,因此需要对Input中方法修改,只返回分割后的,再在Controller中按需求进行去除;
//返回整个电路图链接组成信息
public String[] splitCircuitDiagram() {
input = input.replaceAll("\\[|\\]", " ");
input = input.replaceAll(":|#", "");
//去掉开头结尾空格,防止数组分割多了
input = input.replaceAll("^\\s+", "");
input = input.replaceAll("\\s+$", "");
//将各个元件名字分割
String[] inputTmp = input.split("\\s+");
return inputTmp;
}
3.修改Controller类中把元件放入电路的方法,使得能在放入窗帘和互斥开关时能正确创建对应的对象,同时对于互斥开关,能将引脚2,3对应放入的串联电路名称赋值给互斥开关本身;
//创建元件并放入单条串联电路(以下方法的操作均是对circuitDiagram进行的)
public void inputCircuit() {
String[] inputTmp = input.splitCircuit();
Circuit circuitTmp = new Circuit();
circuitTmp.setName(inputTmp[0]);
String inputTmp2 = inputTmp[0].replaceAll("T", "");
circuitTmp.setNum(Integer.parseInt(inputTmp2));
//跳过IN等符号
for(int i = 2; i < inputTmp.length; i += 2) {
AbstractElectronic electronic = null;
int hasFound = -1;
String inputTmp3 = inputTmp[i].replaceAll("-.*","");
//先在已经有的电子元件中查找,没有查到再新建
for(AbstractElectronic electronic2 : this.circuitDiagram.getElectronics()) {
if(electronic2.getName().equals(inputTmp3)) {
hasFound = 1;
electronic = electronic2;
//特殊判断下是不是互斥开关
if(inputTmp[i].indexOf("H") >= 0) {
if(inputTmp[i + 1].matches("H[0-9]+-2") || inputTmp[i].matches("H[0-9]+-2")) {
((MutexSwitch)electronic).getCircuitInfo()[0] = inputTmp[0];
}
else if(inputTmp[i + 1].matches("H[0-9]+-3") || inputTmp[i].matches("H[0-9]+-3")){
((MutexSwitch)electronic).getCircuitInfo()[1] = inputTmp[0];
}
}
//放入这段电路
circuitTmp.getElectronics().add(electronic);
break;
}
}
//没找到就新建
if(hasFound == -1) {
if(inputTmp[i].indexOf("K") >= 0) {
electronic = new Switch();
}
else if(inputTmp[i].indexOf("F") >= 0) {
electronic = new BinningGovernor();
}
else if(inputTmp[i].indexOf("L") >= 0) {
electronic = new ContinuousGovernor();
}
else if(inputTmp[i].indexOf("B") >= 0) {
electronic = new Incandescent();
electronic.setR(10);
}
else if(inputTmp[i].indexOf("R") >= 0) {
electronic = new Fluorescent();
electronic.setR(5);
}
else if(inputTmp[i].indexOf("D") >= 0) {
electronic = new Fan();
electronic.setR(20);
}
else if(inputTmp[i].indexOf("A") >= 0) {
electronic = new FloorFan();
electronic.setR(20);
}
else if(inputTmp[i].indexOf("S") >= 0) {
electronic = new Curtain();
electronic.setR(15);
}
//为互斥开关时需要看下是哪个接口
else if(inputTmp[i].indexOf("H") >= 0) {
electronic = new MutexSwitch();
if(inputTmp[i + 1].matches("H[0-9]+-2") || inputTmp[i].matches("H[0-9]+-2")) {
((MutexSwitch)electronic).getCircuitInfo()[0] = inputTmp[0];
}
else if(inputTmp[i + 1].matches("H[0-9]+-3") || inputTmp[i].matches("H[0-9]+-3")){
((MutexSwitch)electronic).getCircuitInfo()[1] = inputTmp[0];
}
}
//串联组成时由串联组成的时候
else if(inputTmp[i].indexOf("T") >= 0) {
int hasFound1 = -1;
for(AbstractElectronic circuit : this.getCircuitDiagram().getCircuits()) {
if(circuit.getName().equals(inputTmp3)) {
hasFound1 = 1;
electronic = circuit;
break;
}
}
//没找到时
if(hasFound1 < 0) {
}
}
// //除了互斥开关,其他都要把-后去掉
// if(!inputTmp[i].matches("H[0-9]+-[2|3]")) {
inputTmp[i] = inputTmp[i].replaceAll("-.*","");
// }
//需要先判断下不是In和out等,不然转数字会错
if(inputTmp[i].indexOf("IN") < 0 && inputTmp[i].indexOf("OUT") < 0) {
//设置名字和编号
electronic.setName(inputTmp[i]);
inputTmp[i] = inputTmp[i].replaceAll("K|F|L|B|R|D|A|S|H|T", "");
electronic.setNum(Integer.parseInt(inputTmp[i]));
circuitTmp.getElectronics().add(electronic);
//元件放入
circuitDiagram.getElectronics().add(electronic);
}
}
}
//更新下总电阻
circuitTmp.renew();
//单条串联放入
circuitDiagram.getCircuits().add(circuitTmp);
}
4.对于互斥开关状态的更新要在每条串联电路(包括总电路图)更新时进行,首先判断互斥开关是否在这条电路上,在则赋1接通,不在则赋值99999999表示不接通;从而使该互斥开关能在接下来的更新中状态正确;
@Override
public void renew() {
//更新自己的电压
this.setV(this.getVBefore() - this.getVAfter());
double RTmp = 0;
//先遍历计算电路总电阻
for(AbstractElectronic electronic : electronics) {
RTmp += electronic.getR();
}
this.setR(RTmp);
//查找本路上是否有开关以及开关状态
for(AbstractElectronic electronic : electronics) {
if(electronic.getName().indexOf("K") >= 0) {
if(((AbstractSwitch)electronic).getSwitchStatus() == 0) {
this.setV(0);
//设置断路的电压为-1
this.setVAfter(-1);
this.setVBefore(-1);
//断开开关的路线也不应该算电阻
this.setR(999999);
}
}
else if(electronic.getName().indexOf("H") >= 0) {
//如果目前接通的路不是当前这条
if(!((MutexSwitch)electronic).getCircuitInfo()[((AbstractSwitch)electronic).getSwitchStatus()].equals(this.getName())){
this.setV(0);
//设置断路的电压为-1
this.setVAfter(-1);
this.setVBefore(-1);
//断开开关的路线也不应该算电阻
this.setR(999999);
}
// else {
// if(((AbstractSwitch)electronic).getSwitchStatus() == 0) {
// this.setR(this.getR() + 5);
// }
// else if(((AbstractSwitch)electronic).getSwitchStatus() == 1) {
// this.setR(this.getR() + 10);
// }
// }
}
}
int cot = 0;
AbstractElectronic electronicTmp = null;
//再遍历更新电阻和电压,同时更新电器
for(AbstractElectronic electronic : electronics) {
//当这个串联电路没有断开时
if(this.getR() < 99999) {
if(cot == 0) {
electronic.setVBefore(this.getVBefore());
if(electronic.getVBefore() > 0) {
electronic.setV(electronic.getR() / this.getR() * this.getV());
electronic.setVAfter(electronic.getVBefore() - electronic.getV());
}
electronic.renew();
}
else {
electronic.setVBefore(electronicTmp.getVAfter());
if(electronic.getVBefore() > 0) {
electronic.setV(electronic.getR() / this.getR() * this.getV());
electronic.setVAfter(electronic.getVBefore() - electronic.getV());
}
electronic.renew();
}
}
else {
electronic.setVBefore(0);
electronic.setV(0);
electronic.setVAfter(0);
electronic.renew();
}
cot ++;
electronicTmp = electronic;
}
}
5.对于窗帘的更新,因为开关状态和总灯管亮度有关,所以最后在总电路图renew方法的最后先遍历获取总亮度,再遍历更新所有窗帘;
//遍历此时所有灯,记录总亮度,赋给窗帘
double brightnessTmp = 0;
for(AbstractElectronic electronic : electronics) {
try {
brightnessTmp += ((AbstractLight)electronic).getBrightness();
} catch (ClassCastException e) {
// TODO: handle exception
}
}
for(AbstractElectronic electronic : electronics) {
try {
((AbstractCurtain)electronic).setBrightness(brightnessTmp);
electronic.renew();
} catch (ClassCastException e) {
// TODO: handle exception
}
}
6.完整源代码见NCHU-OOP课程与PTA七到八周作业源代码 - cdz_hy - 博客园 (cnblogs.com)
代码分析:
对本次代码用Source Monitor进行分析:
可以得知代码共1477行,572个语句,分为12个类,平均6.17个方法,方法平均语句数7.55;
从左侧图可以看出代码最大复杂度特别高,在窗帘更新的方法中,这个方法是根据电压和光照设置自身不同的打开程度的,里面确实用了较多if-else来处理,但说实话不太清楚为什么SM判断这个方法比较复杂;代码其他方面都比较适中,还是不错的,需要继续保持;
圈复杂度最高5,集中在1到3;
踩坑总结:
个人认为本题主要难点在于互斥开关的处理上,到底应该新建一个抽象类,应不应该再加一个引脚类和每个元件关联,在互斥开关所在的两条电路放入一个开关还是放入两个开关,对互斥开关的控制应该怎样操作,怎么更新并实现一条线路连通,另一条断开;这些问题实际上都是不好抉择的;
而对于电路链接的状态,多个并联的串联,由于上次的规划在逻辑上实际可以处理,所以本次并没有更改太多电路链接的逻辑;
互斥开关的处理,最后我选择的是放一个开关并在每条电路更新时更新开关状态,先不论应不应该这样实现,这种方式实际上会给我下一次带来非常大的麻烦;
这些在设计之初,开始写代码前需要考虑的东西,还是不能目光太短浅啊;
PTA-oop-8
家居强电电路模拟程序-4:
题目:
智能家居是在当下家庭中越来越流行的一种配置方案,它通过物联网技术将家中的各种设备(如音视频设备、照明系统、窗帘控制、空调控制、安防系统、数字影院系统、影音服务器、影柜系统、网络家电等)连接到一起,提供家电控制、照明控制、电话远程控制、室内外遥控、防盗报警、环境监测、暖通控制、红外转发以及可编程定时控制等多种功能和手段。与普通家居相比,智能家居不仅具有传统的居住功能,兼备建筑、网络通信、信息家电、设备自动化,提供全方位的信息交互功能。请根据如下要去设计一个智能家居强电电路模拟系统。以下题目介绍中加粗的部分为本次迭代在“家居强电电路模拟程序-3”的基础上增加的功能要求。
1、控制设备
本题模拟的控制设备包括:开关、分档调速器、连续调速器、互斥开关。
开关:包括0和1两种状态。
开关有两个引脚,任意一个引脚都可以是输入引脚(接往电源端),而另一个则是输出引脚(接网接地端)。开关状态为0时,无论输入电位是多少,输出引脚电位为0。当开关状态为1时,输出引脚电位等于输入电位。
互斥开关:
互斥开关有3个引脚:1个是汇总引脚,另两个是分支引脚。
开关电路示意图如图1所示,左边是汇总引脚,编号为1;右边两个是分支引脚,右上的输出引脚为2,右下输出引脚为3。图中1、2、3引脚均可以是输入引脚,当1为输入引脚时,2、3引脚为输出引脚;1为输出引脚时,2、3引脚为输入引脚。
互斥开关只有两种状态:开关接往上面的2号引脚、接往下面的3号引脚。开关每次只能接通其中一个分支引脚,而另一个分支引脚处于断开状态。
互斥开关的默认状态为1、2引脚接通,1、3引脚断开。
图1中所示的互斥开关可以反过来接入电路,即汇总引脚接往接地端,两个分支引脚接往电源端。
image.png
图1 互斥开关
为避免短路,互斥开关设置了限流电阻,1、2引脚之间默认电阻为5,1、3引脚之间默认电阻为10。
分档调速器
按档位调整,常见的有3档、4档、5档调速器,档位值从0档-2(3/4)档变化。本次迭代模拟4档调速器,每个档位的输出电位分别为0、0.3、0.6、0.9倍的输入电压。
连续调速器
没有固定档位,按位置比例得到档位参数,数值范围在[0.00-1.00]之间,含两位小数。输出电位为档位参数乘以输入电压。
所有调速器都有两个引脚,一个固定的输入(引脚编号为1)、一个输出引脚(引脚编号为2)。当输入电位为0时,输出引脚输出的电位固定为0,不受各类开关调节的影响。
开关、调速器的初始状态/档位为0。
开关的两个引脚编号为1、2。
除互斥开关外,其他控制设备的电阻为 0。
2、受控设备
本题模拟的受控设备包括:灯、风扇。两种设备都有两根引脚,通过两根引脚电压的电压差驱动设备工作。
灯有两种工作状态:亮、灭。在亮的状态下,有的灯会因引脚电位差的不同亮度会有区别。
风扇在接电后有两种工作状态:停止、转动。风扇的转速会因引脚间电位差的不同而有区别。
本次迭代模拟两种灯具。
白炽灯:
亮度在0~200lux(流明)之间。
电位差为0-9V时亮度为0,其他电位差按比例,电位差10V对应50ux,220V对应200lux,其他电位差与对应亮度值成正比。白炽灯超过220V。
日光灯:
亮度为180lux。
只有两种状态,电位差为0时,亮度为0,电位差不为0,亮度为180。
本次迭代模拟两种风扇。
吊扇:
工作电压区间为80V-150V,对应转速区间为80-360转/分钟。80V对应转速为80转/分钟,150V对应转速为360转/分钟,超过150V转速为360转/分钟(本次迭代暂不考虑电压超标的异常情况)。其他电压值与转速成正比,输入输出电位差小于80V时转速为0。
落地扇:
工作电压区间为 80V-150V,对应转速区间为 80-360 转/分钟;[80V,100V) 对应转速为 80 转/分钟;[100,120)V 对应转速为 160 转/分钟;[120,140)V 对应转速为 260 转/分钟;大于等于 140V 转速 为 360 转/分钟(本次迭代暂不考虑电压超标的异常情况)。
本次迭代模拟一种受控窗帘:
受控串联的电路符号为S,其最低工作电压为50V,电压达到或超过50V,窗帘即可正常工作,不考虑室外光照强度和室内空间大小等因素,窗帘受室内灯光的光照强度控制。
当电路中所有灯光的光照强度总和在[0,50)lux范围内,窗帘全开;
在[50,100)lux范围内,窗帘打开比例为0.8;
在[100,200)lux范围内,窗帘打开比例为0.6;
在[200,300)lux范围内,窗帘打开比例为0.4;
在[300,400)lux范围内,窗帘打开比例为0.2;
在400lux及以上范围内,窗帘关闭。
当电压低于50V,窗帘不工作,默认为全开状态。
如果电路中没有灯或者灯全部关闭,光照强度为0,窗帘处于全开状态。
受控设备电阻:白炽灯的电阻为 10,日光灯的电阻为 5,吊扇的电阻为 20,落地扇的电阻为 20,窗帘电阻为15。
3、输入信息
1)输入设备信息
分别用设备标识符K、F、L、B、R、D、A、H、S、P分别表示开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、落地扇、互斥开关、受控窗帘、二极管(见第6部分说明)。
设备标识用标识符+编号表示,如K1、F3、L2等。
引脚格式:
设备标识-引脚编号,例如:K1-1标识编号为1的开关的1号引脚。
开关、分档调速器、连续调速器的两个引脚编号为1、2。
受控设备的两个引脚编号分别为1、2。
互斥开关的引脚编号已经在互斥开关的介绍部分说明。
约束条件:
不同设备的编号可以相同。
设备信息不单独输入,包含在连接信息中。
2)输入连接信息
一条连接信息占一行,用[]表示一组连接在一起的设备引脚,引脚与引脚之间用英文空格" "分隔。
格式:
"["+引脚号+" "+引脚号+"]"
例如:[K1-1 K3-2]表示K1的1号引脚,K3的2号引脚连接在一起。
约束条件:
不考虑调速器串联到其他调速器的情况。
考虑各类设备的并联接入。例如,K1 的输出接到 L2 的输入,L2 的输出再接其他设备属于串联接线。K1 的输出接到 L2 的输出,同时 K1 的输入接到 L2 的输入,这种情况属于并联。
连接信息不单独输入,包含在线路信息中。
3)输入控制设备调节信息
开关、互斥开关调节信息格式:
#+设备标识K+设备编号,例如:#K2,代表切换K2开关的状态。
#+设备标识H+设备编号,例如:#H2,代表切换H2互斥开关的状态。
分档调速器的调节信息格式:
#+设备标识F+设备编号+"+" 代表加一档,例如:#F3+,代表F3输出加一档。
#+设备标识F+设备编号+"-" 代表减一档,例如:#F1-,代表F1输出减一档。
连续调速器的调节信息格式:
#+设备标识L+设备编号+":" +数值 代表将连续调速器的档位设置到对应数值,例如:#L3:0.6,代表L3输出档位参数0.6。
4)电源接地标识:
VCC,电压220V,GND,电压0V。没有接线的引脚默认接地,电压为0V。
5)输入串联电路信息
一条串联电路占一行,串联电路信息由 n 个连接信息组成,连接信息按从靠电源端到接地端顺序依次输入,连接信息之间用英文空格" "分隔。
串联电路信息格式:
"#T"+电路编号+":"+连接信息+" "+连接信息+...+" "+连接信息
例如:#T1:[IN K1-1] [K1-2 D2-1] [D2-2 OUT] 一个串联电路的第一个引脚是 IN,代表起始端,靠电源。最后一个引脚是 OUT,代表结尾端, 靠接地。
约束条件:
不同的串联电路信息编号不同。
输入的最后一条电路信息必定是总电路信息,总电路信息的起始引脚是 VCC,结束引脚是 GND。
连接信息中的引脚可能是一条串联或并联电路的 IN 或者 OUT。例如:
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT OUT]
#T1:[IN K1-1] [K1-2 T2-IN] [T2-OUT M2-IN] [M2-OUT OUT]
6)输入并联电路信息
一条并联电路占一行,并联电路由其包含的几条串联电路组成,串联电路标识之间用英文空格" "分隔。
格式:
"#M"+电路编号+":"+”[”+串联电路信息+" "+....+" "+串联电路信息+”]”
例如:#M1:[T1 T2 T3]
该例声明了一个并联电路,由 T1、T2、T3 三条串联电路并联而成,三条串联电路的 IN 短接在一起构成 M1 的 IN,三条串联电路的 OUT 短接在一起构成 M1 的 OUT。
在本题中,并联电路M中的串联电路可以包含别的并联电路。
约束条件:
本题不考虑输入电压或电压差超过220V的情况。
输入信息以end为结束标志,忽略end之后的输入信息。
本题中的并联信息所包含的串联电路的信息都在并联信息之前输入,不考虑乱序输入的情况。
只要不因短路而造成无穷大的电流烧坏电路(如电路中的部分短接),都是合理情况。
本次迭代考虑多个并联电路串联在一起的情况。
本题考虑一条串联电路中包含其他串联电路和并联电路的情况。例如:
#T3:[VCC K1-1] [K1-2 T2-IN] [T2-OUT K2-1] [K2-2 T1-IN] [T1-OUT GND]
本例中T1\T2两条串联电路是T3的一个部分,本题考虑这种类型的输入。
4、输出信息:
按开关、分档调速器、连续调速器、白炽灯、日光灯、吊扇、互斥开关、受控窗帘、二极管(见第6部分说明)的顺序依次输出所有设备的状态或参数。每个设备一行。同类设备按编号顺序从小到大输出。
输出格式:
@设备标识+设备编号+":" +设备参数值(控制开关的档位或状态、灯的亮度、风扇的转速,只输出值,不输出单位)+" "+设备所有引脚的电压(按编号从小到大顺序依次输出,电压的小数部分直接丢弃,保留整数输出,电压之间用”-”分隔)
说明:
连续调速器的档位信息保留两位小数,即使小数为0,依然显示两位小数.00。
开关状态为0(打开)时显示turned on,状态为1(合上)时显示closed
如:
@K1:turned on 32-15
@B1:190 68-17
@L1:0.60 220-176
互斥开关按1、2引脚的接通状态显示,1,2接通-1,3断开时显示closed,1,3接通-1,2断开时显示turned on。
如:
@H1:turned on
受控窗帘显示窗帘打开的百分比,如:
@S1:80%
5、家居电路模拟系列所有题目的默认规则
1)当计算电压值等数值的过程中,最终结果出现小数时,用截尾规则去掉小数部分,只保留整数部分。为避免精度的误差,所有有可能出现小数的数值用double类型保存并计算,不要作下转型数据类型转换,例如电压、转速、亮度等,只有在最后输出时再把计算结果按截尾规则,舍弃尾数,保留整数输出。
2)所有连接信息按电路从靠电源端到靠接地端的顺序依次输入,不会出现错位的情况。VCC/IN一定是第一个连接的第一项,GND/OUT一定是最后一个连接的后一项。
3)连接信息如果只包含两个引脚,靠电源端的引脚在前,靠接地端的在后。
4)调速器的输入端只会直连VCC,不会接其他设备。整个电路最多只有连接在电源上的一个调速器,且不包含在并联单路中。
5)本系列题目中元件的管脚除了互斥开关的1引脚,其他所有引脚在电路中最多只出现一次。
6、本题新增内容:
1)增加管脚电压的显示
在输出每个电器的状态信息后,再依次输出该电器每个管脚的电压。(格式详见输出信息部分)
2)电流限制
电器在工作时,过大的电流会引起电器过热,从而烧坏电路。本次迭代,每个元器件都有最大电流的设置,当实时电流超过最大电流时,在该电器输出信息的最后加入提示“exceeding current limit error”,与前面的信息之间用英文空格分隔。
例如:@B1:190 68-17 exceeding current limit error
本题各类电器的最大限定电流如下:
开关20、分档调速器18、连续调速器18、白炽灯9、日光灯5、吊扇12、落地扇14、互斥开关20、受控窗帘12、二极管8。
3)短路检测
如果电路出现无穷大的电流造成短路,所有元器件信息不输出,仅输出提示“short circuit error”
4)并联电路中包含并联
本次迭代考虑并联电路中包含并联电路的情况,即构成并联电路的串联电路可以包含别的并联电路。例如如下输入的电路,并联电路M2的其中一条串联电路T4中包含了另一条并联电路M1:
#T1:[IN D2-1] [D2-2 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
5)二极管
增加二极管元件,其电路特性为:正向导通,反向截止;其电器符号如图4所示,当电流从左至右流过时,二极管导通”conduction”,电阻为0;电流从右至左流动时,二极管截止”cutoff”,电阻无穷大,相当于开关打开。
image.png
图2 二极管符号
二极管的标识符为’P’,左侧管脚编号为1,右侧管脚编号为2。
二极管如果两端电压相等,没有电流流过,分以下两种情况输出:
1、如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之为截止。
2、如果两端电压不为0,二极管导通。
7、设计建议
本题包含以下电路图中的所有连接情况:
image.png
图3 电路示意图
1、电路设备类:描述所有电路设备的公共特征。
2、受控设备类、控制设备类:对应受控、控制设备
3、串联电路类:一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备
4、并联电路类:继承电路设备类,也看成是一个独立的电路设备
其他类以及类的属性、方法自行设计。
image.png
图4:建议设计类图
输入样例1:
在这里给出一组输入。例如:
#T1:[IN P2-2] [P2-1 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M2-IN] [M2-OUT GND]
#K1
#K2
end
输出样例1:
在这里给出相应的输出。例如:
@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:turned on 220-0
@B1:200 220-0 exceeding current limit error
@D1:0 0-0
@H1:closed 0-0-0
@P2:cutoff 0-0
输入样例2:
在这里给出一组输入。例如:
#T1:[IN P2-1] [P2-2 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M2-IN] [M2-OUT GND]
#K1
#K3
#K2
end
输出样例2:
在这里给出相应的输出。例如:
@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220 exceeding current limit error
@B1:200 220-0 exceeding current limit error
@D1:0 220-220
@H1:closed 0-220-220 exceeding current limit error
@P2:conduction 220-220 exceeding current limit error
输入样例3:
在这里给出一组输入。例如:
#T1:[IN P2-2] [P2-1 H1-2] [H1-1 OUT]
#T2:[IN D1-1] [D1-2 H1-3] [H1-1 OUT]
#M1:[T1 T2]
#T4:[IN K3-1] [K3-2 M1-IN] [M1-OUT OUT]
#T5:[IN K1-1] [K1-2 B1-1] [B1-2 OUT]
#M2:[T4 T5]
#T3:[VCC K2-1] [K2-2 M2-IN] [M2-OUT GND]
#K1
#K3
#K2
end
输出样例3:
在这里给出相应的输出。例如:
@K1:closed 220-220 exceeding current limit error
@K2:closed 220-220 exceeding current limit error
@K3:closed 220-220
@B1:200 220-0 exceeding current limit error
@D1:0 220-220
@H1:closed 0-0-220
@P2:cutoff 0-220
输入样例4:
在这里给出一组输入。例如:
#T3:[VCC K2-1] [K2-2 GND]
#K2
end
输出样例4:
在这里给出相应的输出。例如:
short circuit error
输入样例5:
在这里给出一组输入。如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之截止。 例如:
#T3:[VCC K2-2] [K2-1 P1-1] [P1-2 K1-2] [K1-1 GND]
end
输出样例5:
在这里给出相应的输出。例如:
@K1:turned on 0-0
@K2:turned on 0-220
@P1:conduction 0-0
输入样例6:
在这里给出一组输入。如果两端电压为0,二极管的导通/截止状态由接入方向决定,1号引脚靠近电源则状态为导通,反之截止。 例如:
#T3:[VCC K2-2] [K2-1 P1-2] [P1-1 K1-2] [K1-1 GND]
end
输出样例6:
####### 。例如:
@K1:turned on 0-0
@K2:turned on 0-220
@P1:cutoff 0-0
题目分析:
本题尽管纠结了很久,但是最终没有满分,甚至相去甚远,所以以下安排一定不是对的,仅仅是本人在有限的能力下的比较好的解决方式;
本题在上一道的基础上新增二极管,新增对每个引脚的电压的输出,新增每个元件的电流限制,对电流过大的警报,同时还新增了整个电路短路时的提示;在电路状态上,出现了并联中有并联,同时并联中还会出现短路的情况,这无疑会对目前的电路链接和电阻电压更新的处理带来很大的挑战;
对于二极管的处理,新增二极管(Diode)类,继承自抽象开关类,处理更新方法类似互斥开关,通过记录当前接入状态,分别设置不同电阻,实现电路接通或断路的实现;
对于设置每个元件的最大电流并在电流过大时提示,可以对每个具体的元件类新增最大电流的属性maxCurrent,在renew中判断当前电流是否大于最大电流(每个抽象元件已经有了流过本元件电流的属性),以字符串形式输出在status中;而电流的计算,则在每一条串联电路的更新时,计算总电阻,V/R求出,并依次赋值给本电路中的每一个元件;
对于每个引脚的电压输出,由于前几次的电压处理都是先求电阻,再分压,且分压时是通过将第一个元件的输出电压作为下一个元件的输入电压依次赋值的,所以本次迭代中电压这部分不需要做很大的改动;但是对于输出每个引脚的电压,我实际上还是毫无头绪的;
对于每个引脚电压的输出,我最终决定在输入元件并创建对象放入电路中时,记录当前元件的接入状态(对抽象电子元件类新增private int accessState = 0;// 表示接入状态,0时1-2,1时2-1);对于互斥开关,由于有三个引脚,需要做出特殊处理,还是在电路更新时,判断开关是否;但是其他同学都
类图设计:
本题类图设计如下:
方法编写:
代码分析:
对本次代码用Source Monitor进行分析:
这图我看着也绷不住啊,唉,这次的代码实在是写的太差了;
可以得知代码共2025行,625个语句,分为4个类(???),平均15.25个方法,方法平均语句数10.00;
从左侧图可以看出代码最大复杂度较高,在主方法中;代码的嵌套层级深度,平均嵌套层级深度,都极其高,唉,猜测可能是这次对每个元件的renew次数都增加了,在这种类似递归的一个嵌套一个的逻辑下导致深度增长很多;
圈复杂度最高9+,集中在9+,可测试性几乎没有;
但是个人感觉可能是因为本次代码写的逻辑有点混乱导致SM可能给出的结果有一定不准确,毕竟怎么说也不会只有4个类啊;
踩坑总结:
在解决这个题目过程中,遇到了很多挑战。
并联中的并联与短路处理:低估了电路结构复杂性带来的挑战,尤其是在处理并联电路中嵌套并联,以及短路情况时。直接沿用之前的分压计算方法不够灵活,特别是在处理短路路径时,简单的电阻累加和电压分配逻辑不再适用。应该是引入更精细的状态跟踪和电路遍历(具体我也不是很清楚),要确保在遍历过程中能准确识别并处理短路路径,避免电流无限大错误。
二极管的判断处理。虽然通过继承抽象开关类并记录接入状态来模拟二极管理论可行,但后来发现这方面应该出了一些问题,有时候会出现一些精度或者更新不到的情况;(虽然处理了分数也没涨);
引脚电压输出的问题, 我在处理每个引脚电压输出时采取了记录元件接入状态的策略,对于断开的元件记录电阻99999999,接通记录为0,但是这种情况下会导致199.9999被输出为199,所以采取了加0.01的方式,但是好像还是会出现精度问题导致错误;
自己在面对难题时,过于相信自己的判断了,未能充分汲取他人经验。其他同学可能采取了更为高效或直接的策略处理问题,而我却没有积极寻求交流和合作。
七到八周阶段总结:
关于自身:
这两次的题目集说实话都给我带来了很大的挑战,一方面是设计上的问题,开始时的结构不合理,修改了一次,但是其实新的结构没有引脚,依旧存在很多问题。另一方面是对于新增加的需求增添,和新状态的判断上逻辑的处理不清楚,大都是凭感觉自己乱写的,如果想再新加一些电路状态就会异常的困难,完全不清楚要加在哪里;
其实说到底还是结构和逻辑有问题,唉,最后一次花了大量时间还没有得到满意的成绩,着实是狠狠打击到我了,今后一定要考虑好,理顺逻辑关系啊。
虽然题目集到这里就结束了,但是java和面向对象的学习还远远不止,暑期的实训,以后的各种课程,都离不开他们。对于java,仍有非常多需要学习的知识,舍友已经熟练运用的流,我现在都还没怎么接触,种种都需要提高自学能力,尽快学上补上。对于面向对象以及结构的设计,更需要多加学习练习,23种设计模式,是务必要熟练掌握的,暑假需要多看源码多练习设计了啊!
关于课程和作业:
现在设计和结构太差了,唉,自己越学越菜了啊Orz

浙公网安备 33010602011771号