OOP 后三次作业的发寄史

youaremineandwhoisIofyours / 2024-06-06 / 原文

前言

这篇博文总结了我在 Java 课程中的三次编程作业的经验和心得。这三次作业为我大一生活带来了极大的压力,其中仅有一次顺利完成。为了帮助同学们理解我的解题思路和程序框架,我将详细介绍每次作业的设计和实现过程。

首先,这些作业涉及到多种不同的编程任务和问题解决方法。由于编写代码的方法繁琐,再加上时间的限制,我未能在规定时间内完成所有作业。不过,通过这些作业的实践,我积累了宝贵的经验,对代码的模块化设计和异常处理有了更深的理解。

本文将详细讲解每次作业的题目要求、解决思路以及代码框架,同时分享我在编写这些代码时遇到的挑战和解决方案。希望这些内容能对正在学习 Java 的同学们有所帮助,并为大家在编程过程中提供一些借鉴和参考

第一次pta

这次是上一次的第四次迭代,没在规定时间内完成,但是时间外还是写好了。

主类 Main:

通过 Scanner 从标准输入读取命令。
根据命令类型(常规题、多选题、填空题、试卷、学生信息、答卷、删题)创建相应的对象并进行解析。
对不同类型的问题进行存储,并将其存入对应的列表中。
根据命令处理删除操作。
计算每个学生的答卷分数并输出。

类 Question:

这是一个抽象类,包含了问题的基本信息(id、text、ans、status)和一些基本方法(getRegex、parseInput)。
类 Choice、Completion、Common:

继承自 Question 类,每个类代表一种问题类型(多选题、填空题、常规题)。
包含各自的答案检查逻辑(check 方法)。

类 Paper:

表示试卷,包含试卷号和题目信息。
提供解析试卷的方法(parsePaper)和一些辅助方法(如 check、printIsFull)。

类 StudentInfo:

存储学生的基本信息(学生ID和名字)。
提供解析学生信息的方法(parseStudentInfo)和一些辅助方法(如 getStudentName)。

类 AnswerSheet:

表示学生的答卷,包含试卷号、学生ID和答案信息。
提供解析答卷的方法(parseAnswerSheet)和一些辅助方法(如 getScore、setScore)。

类 DeleteQuestion:

表示删除题目操作,包含题目ID。
提供解析删除命令的方法(parseDeleteQuestion)和删除题目逻辑(deleteQuestion)。

类图(因为不太会导图片,所以直接写了)
Main:

属性:
List commons
List choices
List completions
List deleteQuestions
List papers
StudentInfo studentInfo
List answerSheets
方法:
public static void main(String[] args)
类 Question(抽象类):

属性:
int id
String text
String ans
int status
方法:
public String getRegex(int choice)
public String[] parseInput(String input, String regex)
类 Common(继承自 Question):

方法:
public Common()
public Common(int id, String text, String ans, int status)
public String check(String ans)
类 Choice(继承自 Question):

方法:
public Choice()
public Choice(int id, String text, String ans, int status)
public String check(String ans)
类 Completion(继承自 Question):

方法:
public Completion()
public Completion(int id, String text, String ans, int status)
public String check(String ans)
类 Paper:

属性:
String paperNumber
TreeMap<String, Integer> questionInfo
boolean isFull
方法:
public Paper()
public Paper(String paperNumber, TreeMap<String, Integer> questionInfo, boolean isFull)
public boolean isFull()
public void setFull(boolean full)
public void check()
public String getPaperNumber()
public TreeMap<String, Integer> getQuestionInfo()
public void printIsFull()
public void setPaperNumber(String paperNumber)
public void setQuestionInfo(TreeMap<String, Integer> questionInfo)
public Integer getScoreByQuestionNumber(String questionNumber)
public static Paper parsePaper(String input)
public int compareTo(Paper otherPaper)
类 StudentInfo:

属性:
List studentIds
List studentNames
方法:
public StudentInfo()
public StudentInfo(List studentIds, List studentNames)
public List getStudentIds()
public List getStudentNames()
public boolean getStudentId(String id)
public String getStudentName(String id)
public static StudentInfo parseStudentInfo(String input)
类 AnswerSheet:

属性:
String examPaperNumber
String studentId
TreeMap<Integer, String> answers
static TreeMap<Integer, Integer> score
方法:
public AnswerSheet()
public AnswerSheet(String examPaperNumber, String studentId, TreeMap<Integer, String> answers)
public Integer getScore(Integer num)
public void setScore(Integer num, Integer goal)
public String getExamPaperNumber()
public String getStudentId()
public TreeMap<Integer, String> getAnswers()
public static AnswerSheet parseAnswerSheet(String input)
public int compareTo(AnswerSheet o)
类 DeleteQuestion:

属性:
int id
方法:
public DeleteQuestion()
public DeleteQuestion(int id)
public static DeleteQuestion parseDeleteQuestion(String input)
public void deleteQuestion(List<? extends Question> questions, int id)

心得与建议

我的代码在第一次编写的时候因为图省事,很多功能都放在了Main函数当中,需要进行模块化处理,将其分划出来,以便于调试。(也就是所谓的“高耦合度”)

另一方面,存在大量重复代码以及没有异常处理,这点纯粹是因为懒得动脑子。。。。。。最后,被某人告诉我说代码中存在很多硬编码问题,但是我听不懂,最后还是把字符串输入改了一下,部分改为了常量。

第二次pta

这次是新的题面,勉强能写。

Device:抽象基类,包含所有设备的共有特性,如标识符、引脚电压和抽象方法。
Switch:继承自Device,实现一个开关设备,具有开闭状态。
MultiSpeedController:继承自Device,实现一个多档位控制器,具有多个档位。
ContinuousController:继承自Device,实现一个连续控制器,档位值在0到1之间。
IncandescentLamp:继承自Device,实现一个白炽灯,输出电压根据电压差计算。
FluorescentLamp:继承自Device,实现一个荧光灯,输出电压根据电压差计算。
CeilingFan:继承自Device,实现一个吊扇,输出电压根据电压差计算。
Main:主类,处理输入、管理设备和连接、更新设备状态、输出结果。

Device

属性:
String identifier
double pin1Voltage
double pin2Voltage
方法:
Device(String identifier)
String getIdentifier()
abstract void updateState()
void setPin1Voltage(double voltage)
void setPin2Voltage(double voltage)
double getPin1Voltage()
double getPin2Voltage()
abstract String output()

Switch

继承:Device
属性:
boolean isClosed
方法:
Switch(String identifier)
void updateState()
String output()
boolean isClosed()

MultiSpeedController

继承:Device
属性:
int currentGear
static final int MAX_GEAR
方法:
MultiSpeedController(String identifier)
void increaseGear()
void decreaseGear()
void updateState()
String output()
int getCurrentGear()

ContinuousController

继承:Device
属性:
double gearValue
方法:
ContinuousController(String identifier)
void setGearValue(double value)
void updateState()
String output()
double getGearValue()

IncandescentLamp

继承:Device
属性:
int outputVoltage
方法:
IncandescentLamp(String identifier)
void updateState()
String output()

FluorescentLamp

继承:Device
属性:
int outputVoltage
方法:
FluorescentLamp(String identifier)
void updateState()
String output()

CeilingFan

继承:Device
属性:
int outputVoltage
方法:
CeilingFan(String identifier)
void updateState()
String output()

Main

属性:
Map<String, Device> devices
Map<String, List> connections
方法:
void processConnection(String connection)
void createDevice(String id)
void processControl(String control)
void updateDevices()
void outputResults()
static void main(String[] args)

心得与建议
重复代码:在Switch, MultiSpeedController, ContinuousController类中,存在重复的电压更新逻辑,可以提取到基类中。
强制类型转换:使用instanceof和强制类型转换,设计不够优雅。可以使用多态来避免这些检查。
电压更新逻辑的统一性:在updateDevices方法中,电压更新逻辑和电压传递逻辑混杂,建议分离。
异常处理:代码中缺少异常处理,例如在解析输入时,可能会遇到格式错误。
代码注释:可以增加更多有意义的注释,特别是在复杂逻辑部分,以便于理解和维护。
设备创建逻辑:createDevice方法中使用字符串前缀判断设备类型,不够灵活。可以考虑使用工厂模式创建设备实例。
系统扩展性:当前设计对新设备的支持不够灵活,如果需要增加新设备,需要修改多处代码,可以考虑使用设计模式提高扩展性。
通过以上改进,可以使代码更加简洁、易维护、易扩展。

第三次pta
这次就是纯思路框架,没写出来。。。。。。

和前一次进行对比

相同点

基本功能相似:两个题目都涉及智能家居强电电路的模拟,包括控制设备和受控设备的管理。
控制设备类型:两者都涉及开关、分档调速器和连续调速器的模拟。
受控设备类型:都有白炽灯、日光灯和吊扇。
设备状态更新:都需要根据控制设备的状态来更新受控设备的状态。
输入输出格式:输入都是设备信息、连接信息和控制设备的调节信息;输出都是设备的当前状态或参数。

不同点

新增设备:第二个题目新增了落地扇设备。
电路类型:第二个题目增加了串联和并联电路的信息输入,复杂度更高。
电阻考虑:第二个题目引入了电阻的概念,不同设备有不同的电阻值。
并联电路:第二个题目需要处理并联电路的信息和计算。
电路结构复杂度:第二个题目中,电路结构的复杂度增加,需要处理多条串联电路和并联电路的情况。

思路

定义设备类:
定义控制设备类和受控设备类。
控制设备包括开关、分档调速器、连续调速器。
受控设备包括白炽灯、日光灯、吊扇和落地扇。
管理电路连接:
解析输入信息,创建设备和连接信息。
处理串联和并联电路的信息。
更新设备状态:
根据控制设备的调节信息更新设备状态。
计算各设备的输出状态,考虑电压、电阻等因素。
输出结果:
按照要求的顺序输出所有设备的状态或参数。

代码框架

`import java.util.*;

abstract class Device {
protected String identifier;
protected double pin1Voltage = 0;
protected double pin2Voltage = 0;

public Device(String identifier) {
    this.identifier = identifier;
}

public String getIdentifier() {
    return identifier;
}

public void setPin1Voltage(double voltage) {
    this.pin1Voltage = voltage;
}

public void setPin2Voltage(double voltage) {
    this.pin2Voltage = voltage;
}

public double getPin1Voltage() {
    return pin1Voltage;
}

public double getPin2Voltage() {
    return pin2Voltage;
}

public abstract void updateState();
public abstract String output();

}

class Switch extends Device {
private boolean isClosed;

public Switch(String identifier) {
    super(identifier);
    this.isClosed = false;
}

@Override
public void updateState() {
    isClosed = !isClosed;
    pin2Voltage = isClosed ? pin1Voltage : 0;
}

@Override
public String output() {
    return "@" + identifier + ":" + (isClosed ? "closed" : "turned on");
}

}

class MultiSpeedController extends Device {
private int currentGear;
private static final int MAX_GEAR = 3;

public MultiSpeedController(String identifier) {
    super(identifier);
    this.currentGear = 0;
}

public void increaseGear() {
    if (currentGear < MAX_GEAR) {
        currentGear++;
    }
}

public void decreaseGear() {
    if (currentGear > 0) {
        currentGear--;
    }
}

@Override
public void updateState() {
    pin2Voltage = (pin1Voltage * currentGear * 0.3);
}

@Override
public String output() {
    return "@" + identifier + ":" + currentGear;
}

}

class ContinuousController extends Device {
private double gearValue;

public ContinuousController(String identifier) {
    super(identifier);
    this.gearValue = 0.00;
}

public void setGearValue(double value) {
    if (value >= 0.00 && value <= 1.00) {
        this.gearValue = value;
    }
}

@Override
public void updateState() {
    pin2Voltage = (pin1Voltage * gearValue);
}

@Override
public String output() {
    return "@" + identifier + ":" + String.format("%.2f", gearValue);
}

}

class IncandescentLamp extends Device {
private int outputVoltage;
private final int resistance = 10;

public IncandescentLamp(String identifier) {
    super(identifier);
}

@Override
public void updateState() {
    double voltageDifference = Math.abs(pin1Voltage - pin2Voltage);
    if (voltageDifference > 220) {
        outputVoltage = 200;
    } else if (voltageDifference >= 10) {
        outputVoltage = 50 + (int) ((200.0 - 50) / (220.0 - 10.0) * (voltageDifference - 10));
    } else {
        outputVoltage = 0;
    }
}

@Override
public String output() {
    return "@" + identifier + ":" + outputVoltage;
}

}

class FluorescentLamp extends Device {
private int outputVoltage;
private final int resistance = 5;

public FluorescentLamp(String identifier) {
    super(identifier);
}

@Override
public void updateState() {
    double voltageDifference = Math.abs(pin1Voltage - pin2Voltage);
    outputVoltage = voltageDifference > 0 ? 180 : 0;
}

@Override
public String output() {
    return "@" + identifier + ":" + outputVoltage;
}

}

class CeilingFan extends Device {
private int outputVoltage;
private final int resistance = 20;

public CeilingFan(String identifier) {
    super(identifier);
}

@Override
public void updateState() {
    double voltageDifference = Math.abs(pin1Voltage - pin2Voltage);
    if (voltageDifference < 80) {
        outputVoltage = 0;
    } else if (voltageDifference > 150) {
        outputVoltage = 360;
    } else {
        outputVoltage = 80 + (int) (((360.0 - 80) / (150.0 - 80) * (voltageDifference - 80)));
    }
}

@Override
public String output() {
    return "@" + identifier + ":" + outputVoltage;
}

}

class FloorFan extends Device {
private int outputVoltage;
private final int resistance = 20;

public FloorFan(String identifier) {
    super(identifier);
}

@Override
public void updateState() {
    double voltageDifference = Math.abs(pin1Voltage - pin2Voltage);
    if (voltageDifference < 80) {
        outputVoltage = 0;
    } else if (voltageDifference >= 80 && voltageDifference < 100) {
        outputVoltage = 80;
    } else if (voltageDifference >= 100 && voltageDifference < 120) {
        outputVoltage = 160;
    } else if (voltageDifference >= 120 && voltageDifference < 140) {
        outputVoltage = 260;
    } else {
        outputVoltage = 360;
    }
}

@Override
public String output() {
    return "@" + identifier + ":" + outputVoltage;
}

}

class SerialCircuit {
private List devices = new ArrayList<>();

public void addDevice(Device device) {
    devices.add(device);
}

public void updateDevices() {
    for (Device device : devices) {
        device.updateState();
    }
}

public List<Device> getDevices() {
    return devices;
}

}

class ParallelCircuit extends SerialCircuit {
private List serialCircuits = new ArrayList<>();

public void addSerialCircuit(SerialCircuit circuit) {
    serialCircuits.add(circuit);
}

@Override
public void updateDevices() {
    for (SerialCircuit circuit : serialCircuits) {
        circuit.updateDevices();
    }
}

}

public class Main {
private static Map<String, Device> devices = new LinkedHashMap<>();
private static List serialCircuits = new ArrayList<>();
private static List parallelCircuits = new ArrayList<>();

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    Main system = new Main();
    boolean firstInput = true;

    while (scanner.hasNextLine()) {
        String line = scanner.nextLine();
        if (line.equals("end")) {
            break;
        }
        if (line.startsWith("#T")) {
            system.processSerialCircuit(line);
        } else if (line.startsWith("#M")) {
            system.processParallelCircuit(line);
        } else if (line.startsWith("#")) {
            system.processControl(line);
        }
    }

    system.updateAllCircuits();
    system.outputResults();
}

private void processSerialCircuit(String line) {
    String[] parts = line.substring(4).split(" ");
    SerialCircuit circuit = new SerialCircuit();
    for (String part : parts) {
        String[] pins = part.substring

`

总结

通过这三次 Java 编程作业,我深刻体会到了编程的复杂性和挑战性。尽管过程中遇到了许多困难,但每次作业都帮助我提升了编程技能和问题解决能力。

第一次 PTA 作业 主要涉及问题的解析和存储、学生答卷的评分等基本操作,尽管时间紧迫,但最终在时间外完成了任务。通过这次作业,我学会了如何使用类和对象来组织代码,并认识到代码模块化和减少耦合的重要性。

第二次 PTA 作业 增加了设备管理和状态更新的复杂度,我在编写代码时遇到了重复代码和异常处理不足的问题。通过这次作业,我学会了如何通过设计模式来改进代码的扩展性和维护性。

第三次 PTA 作业 虽然没有完全实现,但提供了一个复杂的智能家居强电电路模拟的框架。通过对比与前一次作业的不同点,我进一步理解了复杂系统的设计思路和多态性的应用。

在这些作业中,我不仅巩固了 Java 编程的基础知识,还学会了如何应对和解决实际编程中的各种问题。我意识到,编程不仅需要扎实的技术基础,更需要细致的思考和不断的优化。希望通过不断的学习和实践,能够进一步提升自己的编程能力和专业素养