OOP第三次Blog作业
前言
知识点
这两次的pta作业对于类之间的设计要求很高,很考验我对于类的设计。在这两次的pta作业中,都以继承作为背景,考察了对于继承中相关概念的理解。例如使用继承来扩展上一次的程序,同时加入一些特有方法和重写父类里面的一些方法;多态的使用,使用多态来调取方法时,要注意只能调取公共的方法,不能调取子类特有的方法,如果要调用子类特有的方法,那就必须使用强制类型转换,在使用强制类型转换时,最好用instanceof关键字判断该对象是不是转换后类的实例。同时依旧考察了对于使用正则表达式解析输入信息,利用解析的信息来创建对象。对于对象的储存,考察了集合相关的知识,对于数据的要求不同,要选择恰当的集合来存储元素,例如ArrayList是一个动态数组,可以灵活添加元素,而HashMap可以储存键值对,同时保证键的唯一性,对于去除重复元素可以处理。
题量和难度
题量虽然不是很大,但难度一点都不小。需要考虑的情况越来越复杂,如果没有把类设计好,那每迭代一次都要在上一次的基础上大改,这显然是很难的。
设计与分析
家居强电电路模拟程序-3
新增需求:
引入了互斥开关和受控窗帘,互斥开关有三个引脚,开始时,默认1,2引脚相连窗帘打开程度受室内光照强度影响。考虑多个并联电路串联在一起的情况,本题考虑一条串联电路中包含其他串联电路的情况。
设计:
互斥开关
因为出现了互斥开关,所以先让互斥开关类继承设备类,为互斥开关新增两个数据域,一个记录引脚2所在的串联电路,另一个记录引脚3所在的串联电路,这两个数据域是服务于后续电路是否开路判断的。新的数据域如下:
String first;
String second;
因为互斥开关有三个引脚,还可能反着接,所以对于连接信息的解析做一些调整,在主函数中,拿到设备引脚信息时,判断该信息是否以H开头,如果是,则判断该引脚是2还是3,如果是1,跳过,如果是2或3,则初始化相应的数据与first或second。代码如下:
if (m.group().contains("H")) {
hs.put(m.group(1), (H) d);
int num = Integer.parseInt(m.group(2));
if (num == 2)
((H) d).setFirst(t);
else if (num == 3)
((H) d).setSecond(t);
else
continue;
}
同时,还需在连接类中的判断电路状态的方法新增互斥开关判断,考虑互斥开关引脚的接入情况,如果1,2引脚相连,那么判断该连接对象的名字是不是first数据域里面保存的字符串,如果是,那么电路不是开路,处理1,3引脚也是同理。
代码如下:
public boolean isAllClose() {
if (!allMClose())
return false;
int cnt = 0;
int open = 0;
for (Device value : sd) {
if (value instanceof K) {
cnt++;
K k = (K) value;
if (k.getIsOpen() == 1) {
open++;
}
} else if (value instanceof H) {
cnt++;
H h = (H) value;
if (h.first != null && h.getIsOpen() == 1 && h.first.equals(getName()))
open++;
else if (h.second != null && h.getIsOpen() == 0 && h.second.equals(getName()))
open++;
} else if (value instanceof Connection) {
if (!((Connection) value).isAllClose())
return false;
}
}
return cnt == open;
}
受控窗帘
对于受控窗帘,先创建受控窗帘类继承设备类,给窗帘类设计一个数据域,记录所有设备中的所有灯的集合,所有类共享该数据域。同时设计一个方法,记录这些灯的亮度总和,类的设计如下:
class S extends Device {
public static ArrayList<Device> d;
private double iu;
public S(int id, String name) {
super(id, name);
r = 15;
compare = 9;
}
@Override
public double dy(double in,double I) {
this.iu = I * r;
return iu;
}
//获得总的光照强度
public double lightCount() {
double sum = 0;
for (Device device : d) {
if (device instanceof Light) {
sum += ((Light) device).getBrightness();
}
}
return sum;
}
public void display() {
double sumLight = lightCount();
double openCount;
if (iu < 50) {
openCount = 1;
} else {
if (sumLight < 50 && sumLight >= 0)
openCount = 1;
else if (sumLight < 100 && sumLight >= 50)
openCount = 0.8;
else if (sumLight < 200 && sumLight >= 100)
openCount = 0.6;
else if (sumLight < 300 && sumLight >= 200)
openCount = 0.4;
else if (sumLight < 400 && sumLight >= 300)
openCount = 0.2;
else
openCount = 0;
}
System.out.println("@S" + getId() + ":" + (int) (openCount * 100) + "%");
}
}
多个并联电路串联
这个要求解决起来很简单,只需在主函数里面加点判断就行,如果是并联电路,那么不用创建对象,在并联电路集合中拿到该并联电路。
代码如下:
else if (m.group().contains("M")){
d = sp.get(m.group(1));
}
同时,在连接类中,增加一个判断所有并联电路是否闭合的方法
代码如下:
public boolean allMClose() {
int cnt = 0;
int num = 0;
for (Device device : sd) {
if (device instanceof Paralle) {
cnt++;
if (!((Paralle) (device)).isOpen())
num++;
}
}
return cnt == num;
}
串联电路中包含其他串联电路
这个也是加点判断也就解决了,在主函数中,判断拿到的信息是不是以T开头
else if (m.group().contains("T")) {
d = connections.get(m.group(1));
}
同时在判断总电路是否闭合加上判断
else if (value instanceof Connection) {
if (!((Connection) value).isAllClose())
return false;
}
并且,在计算总电路电阻时,也要加上判断
public double sumR() {
double sum = 0;
if (isAllClose()) {
for (Device value : sd) {
if (value instanceof Paralle)
sum += ((Paralle) value).sumR();
else if (value instanceof Connection)
sum += ((Connection) value).sumR();
else
sum += value.r;
}
}
return sum;
}
相关报表及类图
| Method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| A.A(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| B.B(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.Connection(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.I(double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.add(Device) | 0.0 | 1.0 | 1.0 | 1.0 |
| D.D(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.Device() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.Device(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.display() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.dy(double, double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.getId() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| F.F(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| F.getCount() | 0.0 | 1.0 | 1.0 | 1.0 |
| H.H(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| H.getIsOpen() | 0.0 | 1.0 | 1.0 | 1.0 |
| H.setFirst(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| H.setSecond(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| K.K(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| K.getIsOpen() | 0.0 | 1.0 | 1.0 | 1.0 |
| L.L(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| L.getCount() | 0.0 | 1.0 | 1.0 | 1.0 |
| L.setCount(double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Light.Light(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Light.getBrightness() | 0.0 | 1.0 | 1.0 | 1.0 |
| Light.setBrightness(double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Paralle.add(Connection) | 0.0 | 1.0 | 1.0 | 1.0 |
| R.R(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| S.S(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| S.dy(double, double) | 0.0 | 1.0 | 1.0 | 1.0 |
| A.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| B.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| Connection.dy(double) | 1.0 | 1.0 | 2.0 | 2.0 |
| D.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| F.add() | 1.0 | 1.0 | 1.0 | 2.0 |
| F.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| F.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| F.sub() | 1.0 | 1.0 | 1.0 | 2.0 |
| H.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| H.setIsOpen() | 1.0 | 1.0 | 1.0 | 2.0 |
| H.setR() | 1.0 | 1.0 | 1.0 | 2.0 |
| K.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| K.setIsOpen() | 1.0 | 1.0 | 1.0 | 2.0 |
| L.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| L.dy(double) | 1.0 | 1.0 | 1.0 | 2.0 |
| Main.tmName(String) | 1.0 | 2.0 | 2.0 | 2.0 |
| R.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| B.dy(double, double) | 2.0 | 1.0 | 1.0 | 3.0 |
| Device.compareTo(Device) | 2.0 | 2.0 | 2.0 | 2.0 |
| H.display() | 2.0 | 1.0 | 1.0 | 3.0 |
| K.display() | 2.0 | 1.0 | 1.0 | 3.0 |
| Main.find(String, ArrayList) | 3.0 | 3.0 | 2.0 | 3.0 |
| Paralle.dy(double, double) | 3.0 | 1.0 | 3.0 | 3.0 |
| Paralle.isOpen() | 3.0 | 1.0 | 2.0 | 3.0 |
| R.dy(double, double) | 3.0 | 1.0 | 2.0 | 3.0 |
| S.lightCount() | 3.0 | 1.0 | 3.0 | 3.0 |
| D.dy(double, double) | 5.0 | 1.0 | 1.0 | 5.0 |
| Connection.allMClose() | 6.0 | 1.0 | 3.0 | 4.0 |
| Paralle.sumR() | 6.0 | 1.0 | 3.0 | 5.0 |
| A.dy(double, double) | 8.0 | 1.0 | 1.0 | 9.0 |
| Connection.connectionAll() | 8.0 | 2.0 | 5.0 | 6.0 |
| Connection.sumR() | 8.0 | 1.0 | 5.0 | 5.0 |
| Device.init(String) | 10.0 | 1.0 | 11.0 | 11.0 |
| S.display() | 14.0 | 1.0 | 1.0 | 12.0 |
| Connection.isAllClose() | 18.0 | 7.0 | 10.0 | 14.0 |
| Main.main(String[]) | 87.0 | 17.0 | 31.0 | 33.0 |
| Class | OCavg | OCmax | WMC |
|---|---|---|---|
| A | 3.0 | 6.0 | 9.0 |
| B | 2.0 | 3.0 | 6.0 |
| Connection | 3.5 | 10.0 | 28.0 |
| D | 2.3333333333333335 | 4.0 | 7.0 |
| Device | 2.2222222222222223 | 11.0 | 20.0 |
| F | 1.6666666666666667 | 2.0 | 10.0 |
| H | 1.625 | 3.0 | 13.0 |
| K | 1.8 | 3.0 | 9.0 |
| L | 1.4 | 2.0 | 7.0 |
| Light | 1.0 | 1.0 | 3.0 |
| Main | 11.666666666666666 | 30.0 | 35.0 |
| Paralle | 3.0 | 5.0 | 12.0 |
| R | 2.0 | 3.0 | 6.0 |
| S | 3.0 | 7.0 | 12.0 |
| Total | 177.0 | ||
| Average | 2.6417910447761193 | 6.428571428571429 | 12.642857142857142 |

家居强电电路模拟程序-4
新增需求
引入二极管和要求输出每个引脚的电压,还有并联电路里面可以包含并联电路,还有对于电路中出现短路情况的判断,以及出现超过电器的额定电流的情况。
设计
二极管
首先先创建一个二极管类继承电器类,为其新增数据域来判断二极管是否导通。
设计如下:
class P extends Device{
boolean order;
public P(boolean order,int id, String name) {
super(id, name);
if (order){
r=0;
this.order=true;
}
r=100000000;
compare = 10;
}
@Override
public double dy(double in,double I) {
if (I>8) current=true;
this.in=in;
out=this.in;
return 0;
}
public void display(){
String s=order?"conduction":"cutoff";
String io=" "+(int)in+"-"+(int)out;
System.out.println("@P" + getId() + ":"+s+io+(!current?"":" exceeding current limit error"));
}
}
并联电路包含并联电路
这只需在主函数里面做一点判断就可以,如下:
else if (s.startsWith("#M")) {
//处理并联电路
Paralle paralle = new Paralle();
//根据正则表达式匹配的字符找到对应的串联电路
String regex = "(T\\d+)";
Pattern pa = Pattern.compile(regex);
Matcher m = pa.matcher(s);
while (m.find()) {
Connection d = connections.get(m.group(1));
if (d != null)
paralle.add(d);
}
sp.put(tmName(s), paralle);
}
电路中出现短路的情况
这个很好判断,出现短路,那就是某条串联电路闭合1,但是该条线路总电阻为0,由此就可以判断是否发生断路情况。如下:
public void shortCur(){
for (Device device : sd) {
if (device instanceof Paralle){
ArrayList<Connection>sp=((Paralle)device).para;
for (Connection connection : sp) {
if (connection.isAllClose()&&connection.sumR()==0){
isShort=true;
break;
}
}
}
}
}
超过电器的额定电压
这个很好处理,只要每个设备重写父类的方法就可以实现,拿到电路,然后和额定电流比较,就完成了判断。
相关报表及类图
| Method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| A.A(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| B.B(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.Connection(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.I(double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.add(Device) | 0.0 | 1.0 | 1.0 | 1.0 |
| Connection.setIsOpen() | 0.0 | 1.0 | 1.0 | 1.0 |
| D.D(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.Device() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.Device(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.display() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.dy(double, double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.getId() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.getName() | 0.0 | 1.0 | 1.0 | 1.0 |
| Device.setName(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| F.F(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| F.getCount() | 0.0 | 1.0 | 1.0 | 1.0 |
| H.H(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| H.getIsOpen() | 0.0 | 1.0 | 1.0 | 1.0 |
| H.setFirst(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| H.setSecond(String) | 0.0 | 1.0 | 1.0 | 1.0 |
| K.K(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| K.getIsOpen() | 0.0 | 1.0 | 1.0 | 1.0 |
| L.L(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| L.getCount() | 0.0 | 1.0 | 1.0 | 1.0 |
| L.setCount(double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Light.Light(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Light.getBrightness() | 0.0 | 1.0 | 1.0 | 1.0 |
| Light.setBrightness(double) | 0.0 | 1.0 | 1.0 | 1.0 |
| Paralle.add(Connection) | 0.0 | 1.0 | 1.0 | 1.0 |
| R.R(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| S.S(int, String) | 0.0 | 1.0 | 1.0 | 1.0 |
| Test.main(String[]) | 0.0 | 1.0 | 1.0 | 1.0 |
| A.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| B.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| Connection.dy(double, double) | 1.0 | 1.0 | 2.0 | 2.0 |
| D.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| F.add() | 1.0 | 1.0 | 1.0 | 2.0 |
| F.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| F.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| F.sub() | 1.0 | 1.0 | 1.0 | 2.0 |
| H.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| H.setIsOpen() | 1.0 | 1.0 | 1.0 | 2.0 |
| H.setR() | 1.0 | 1.0 | 1.0 | 2.0 |
| K.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| K.setIsOpen() | 1.0 | 1.0 | 1.0 | 2.0 |
| L.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| L.dy(double) | 1.0 | 1.0 | 1.0 | 2.0 |
| Main.tmName(String) | 1.0 | 2.0 | 2.0 | 2.0 |
| P.P(boolean, int, String) | 1.0 | 1.0 | 1.0 | 2.0 |
| P.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| R.display() | 1.0 | 1.0 | 1.0 | 2.0 |
| S.dy(double, double) | 1.0 | 1.0 | 1.0 | 2.0 |
| B.dy(double, double) | 2.0 | 1.0 | 1.0 | 3.0 |
| Device.compareTo(Device) | 2.0 | 2.0 | 2.0 | 2.0 |
| H.display() | 2.0 | 1.0 | 1.0 | 3.0 |
| K.display() | 2.0 | 1.0 | 1.0 | 3.0 |
| P.display() | 2.0 | 1.0 | 1.0 | 3.0 |
| Main.find(String, ArrayList) | 3.0 | 3.0 | 2.0 | 3.0 |
| Paralle.dy(double, double) | 3.0 | 1.0 | 3.0 | 3.0 |
| Paralle.isOpen() | 3.0 | 1.0 | 2.0 | 3.0 |
| R.dy(double, double) | 3.0 | 1.0 | 2.0 | 3.0 |
| S.lightCount() | 3.0 | 1.0 | 3.0 | 3.0 |
| D.dy(double, double) | 5.0 | 1.0 | 1.0 | 5.0 |
| Connection.allMClose() | 6.0 | 1.0 | 3.0 | 4.0 |
| Paralle.sumR() | 6.0 | 1.0 | 3.0 | 5.0 |
| A.dy(double, double) | 8.0 | 1.0 | 1.0 | 9.0 |
| Connection.connectionAll() | 8.0 | 2.0 | 5.0 | 6.0 |
| Connection.sumR() | 9.0 | 1.0 | 5.0 | 6.0 |
| Connection.shortCur() | 11.0 | 5.0 | 5.0 | 6.0 |
| Device.init(String) | 11.0 | 1.0 | 12.0 | 12.0 |
| S.display() | 15.0 | 1.0 | 1.0 | 13.0 |
| Connection.isAllClose() | 22.0 | 7.0 | 10.0 | 16.0 |
| Main.main(String[]) | 100.0 | 18.0 | 33.0 | 37.0 |
| Total | 246.0 | 105.0 | 151.0 | 220.0 |
| Average | 3.3698630136986303 | 1.4383561643835616 | 2.0684931506849313 | 3.0136986301369864 |
| Class | OCavg | OCmax | WMC |
|---|---|---|---|
| A | 3.0 | 6.0 | 9.0 |
| B | 2.0 | 3.0 | 6.0 |
| Connection | 3.7 | 12.0 | 37.0 |
| D | 2.3333333333333335 | 4.0 | 7.0 |
| Device | 2.3333333333333335 | 12.0 | 21.0 |
| F | 1.6666666666666667 | 2.0 | 10.0 |
| H | 1.625 | 3.0 | 13.0 |
| K | 1.8 | 3.0 | 9.0 |
| L | 1.4 | 2.0 | 7.0 |
| Light | 1.0 | 1.0 | 3.0 |
| Main | 13.0 | 34.0 | 39.0 |
| P | 2.3333333333333335 | 3.0 | 7.0 |
| Paralle | 3.0 | 5.0 | 12.0 |
| R | 2.0 | 3.0 | 6.0 |
| S | 3.5 | 8.0 | 14.0 |
| Test | 1.0 | 1.0 | 1.0 |
| Total | 201.0 | ||
| Average | 2.7534246575342465 | 6.375 | 12.5625 |

踩坑心得
1.在判断总的电路信息时,没有考虑到串联电路的多层包含
改进后:
public double dy(double in,double I) {
double v=in;
for (Device device : sd) {
double x=device.dy(v,I);
v-=x;
}
return 0;
}
每个设备都有dy方法,如果出现多层串联包含,那么会发生递归调用,可以实现预期效果。
2.对于输出信息没有按顺序来输出
改进后:
public int compareTo(Device o) {
if (o.compare != this.compare)
return this.compare - o.compare;
else
return this.getId() - o.getId();
}
即重写设备类的比较方法,然后调用sort方法进行排序
改进建议
1.对于数据的解析,可以使用正则表达式来处理,但全部放在主函数中处理,显得主函数过于臃肿,可以适当抽取成方法,在主函数调取方法来实现数据的解析。
2.对于对象的存储,要选择合适的集合,例如对于在上述程序中的设备集合,就可以将储存设备集合的ArrayList改为HashMap,这样可以方便后续的查找,就不用特意写一个方法来查找设备。
总结
通过这最后两次的pta作业,我开始对软件工程问题从简单到复杂变换的过程有了一定的认识。通过pta的练习,我感受到了自己的能力有待提高,在今后的学习中,我要去慢慢提升自己的能力。
浙公网安备 33010602011771号