OOP第二次Blog

前言

(1) 第四次题集的第一题已经经过了三次迭代,需要考虑到的情况越来越复杂,难度也越来越大,这让我感受到面向对象编程的基本原则的重要性,此前每一次迭代都应该谨慎,切忌为了偷懒就破坏类之间的关系(我第二次迭代就偷懒过了所有测试点,然后最后一次就狂改)。

(2) 第五次题集只有三道题,也是第一次迭代难度不大,但是进过前面几次大作业的磨练,我对类的使用明显愈发熟练,本次大作业用到了抽象类,我将电路设备定义为了抽象类,很轻松的AC这道题。

​ 然后是这题集的第三题,首次接触了集合类型,这道题是改错题,声明类型是Collection,实际类型是ArrayList,然后使用迭代器遍历所以员工,难度一般。

(3) 第六次题集只有一道题(看起来挺唬人),难度也没有很大,经过第一次迭代,加入了并联电路,电路设备也变多了,但是有一个关于精度的计算很难考虑到,花了很长时间调试。

第四次题集

设计与分析:

本次题集除了第三题其他都是很基础的题目,就分析一下最后一题,以下是类图:

本次大作业我设计的主要的几个类分别是

(1) 题目类(Question):用于保存一道题目的信息以及处理的方法。(与系列 1 相同,无变化)

private int num;// 题号

private String content, // 题目内容

standardAnswer;// 标准答案

boolean matchingStandardAnswers(String answer):判断是否符合标准答案

boolean isValid=true;//是否是有效的题目

void disabled() //当题目被删除,设置题目为失效状态

ArrayList answers //记录所有引用了该题目的答案

(2)试卷题目类(Question_Paper):用于保存试卷中的题目信息。由于试卷中的题目序号与题

目本身的题号不一致。且题目在不同试卷中的分值可能不一样,因此,设计试卷题目类。

int p_q_num;//试卷中题目的顺序号

Question question;//题目类的对象,保存题目信息

int question_score;// 题目分值

int judge_markAnswer(String answer) // 判断题目得分

(3)试卷类(TestPaper):保存和处理一张试卷的信息以及处理的方法,

int questionNum;// 题目数量

HashMap<String, Question_Paper> questions;//题目清单

void inputQuestion(int num, Question question):添加一道题目

void printQuestions():输出题目的内容~标准答案

boolean markQuestion(int num, String answer):判断第 num 题的正确性。

int sum-保存总分

int questionQuantity-保存题目数量

int getSum()****:获得总分

(4)答案类(Answer):用于保存答卷中一道答案的信息。

Question_Paper question;

String answer;

boolean mark;// 每一题的正确性

int score=0;// 每一题的得分

void calScore()//计算得分

void disable() //答案对应的题目失效,判分为 0

(5)答卷类(AnswerPaper):保存和处理一张答卷的信息以及处理的方法

TestPaper paper;//试卷信息

String[] answers;//每一题的答案信息boolean[] marks;//每一题的判题结果(对/错)

void printQ_A(int num):输出第 num 题的题目和答案(卷面答案,非标准答案)

boolean getJudge(int num):获得第 num 题的判题结果

void printJudges() :// 输出所有的得分以及总分,以空格分隔

String stuNum;// 学号

void** printErrorNumQuestion(Answer answer) // 输出试卷中错误题目号的题目

void** printInvalidQuestion(Answer answer)// 输出失效题目信息

(5)学生类(Student):保存学生的信息

String stuNum, stuName;

踩坑心得:

(1) 首先这次的大作业,我最后还有一个测试点没有过,现在我弄明白了,但是时间已经过了,这个题目的空白卷输入,就是只有一个卷子,没有题目序号,应该按正常的卷子输出,我的正则表达式有问题,没有捕捉到这种情况。

例如:

应该将这种情况应该按照正常答卷的情况输出,不能当做错误格式判断,这里也体现了下面的错误,判断格式错误。

(2) 我这次又犯了上次同一个错误,正则表达式写错了,导致捕捉不准确。

public static boolean checkquestion(String str)
    {
        String regstr="^#N:\\d*\\s*#Q:.*#A:.*";
        Pattern pattern= Pattern.compile(regstr);
        Matcher matcher=pattern.matcher(str);
        if(matcher.find())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    public static boolean checktest(String str)
    {
        String regstr1="(\\d*)-(\\d*)";
        Pattern pattern1=Pattern.compile(regstr1);
        Matcher matcher1=pattern1.matcher(str);

        String regstr2="^#T:\\s*\\d+\\s*((\\d+\\s*-\\s*\\d+\\s*)+)$";
        Pattern pattern2=Pattern.compile(regstr2);
        Matcher matcher2=pattern2.matcher(str);
        if(matcher2.find())
        {
            return true;
        }
        else
        {
            return false;
        }
    }
    public static boolean checkstudent(String str)
    {

        String regstr2="^#X:\\s*\\d+\\s(.*?)+(?:-\\d+\\s(.*?)+)*$";
        Pattern pattern1=Pattern.compile(regstr2);
        Matcher matcher1=pattern1.matcher(str);
        if(matcher1.find())
        {
            return true;
        }
        else
        {
            return false;
        }
    }

这几个check方法最后在同学的帮助下终于是改对了,下一次一定要仔细读取题目意思,谨慎考虑好之后在开始,不然写到一半出了问题很崩溃的。

改进建议:

这次写的大作业,还是出现前三次的问题,就是类之间的关系有些模糊不清,写到后面经常性用错,但是比起前几次的乱七八糟的代码,至少类的功能分的清楚了。

(1) 这次大作业如果将同学与答卷号码用HashMap保存起来,后续只需要通过迭代器就可以遍历所以答卷和学生,不用再像现在这样遍历所以答卷找同学,可以增强代码的可读性,而且代码也会更简洁,维护起来也容易。

(2) 试卷题目类也可以使用List泛型代替ArraysList存储试卷与题目的关系,这样可以直接使用Collections.sort方法进行排序。

第五次题集:

设计与分析:

​ 首先是这次题集的第一题,这是第一次出现,还没有进行迭代,特殊条件比较多难度一般,以下是类图:

这里主要设计了两个类:

(1) 电路设备类(Equipment):描述所有电路设备的公共特征。

abstract class Equipment {
    int switchstyle;//如果是开关 开关的状态

    public int getSwitchstyle() {
        return switchstyle;
    }


    public boolean IfPathway()
    {
        return false;
    }
    double voltage;//设备分到的电压

    public double getVoltage() {
        return voltage;
    }

    abstract public void setVoltage(double c);

    double resistor;//电阻

    abstract double getResistor();

    public double getContact1() {
        return contact1;
    }

    public void setContact1(double contact1) {
        this.contact1 = contact1;
    }

    String name;//设备名

    public String getName() {
        return name;
    }

    double contact1;//触脚1的电压

    public double getContact2() {
        return contact2;
    }

    public void setContact2(double contact2) {
        this.contact2 = contact2;
    }

    double contact2;//触脚2的电压

    abstract void display();//输出设备的状态

    abstract void close();

}

(2) 串联电路类(Series):一条由多个电路设备构成的串联电路,也看成是一个独立的电路设备。以下是部分代码:

class Series {
    public double getVoltage() {
        return voltage;
    }

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

    private double voltage;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;

    public void VoltageDivision()
    {
        double aver=getVoltage()/getResistor();
        for(int i=0;i<list.size();i++)
        {
            Equipment e= list.get(i);
            if(e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)
                continue;
            else
            {
                e.setVoltage(aver*e.getResistor());
            }
        }
    }

    private double resistor;

    public double getResistor() {
        resistor = 0;
        for (int i = 0; i < list.size(); i++) {
            Equipment e = list.get(i);
            if (e instanceof Switch || e instanceof Governor || e instanceof ContinueGovernor)
                continue;
            else
                resistor += e.getResistor();
        }
        return resistor;
    }
}

将设备类定义为抽象类,其余所有电器继承与设备类,然后使用串联电路类,然后将每个电路元件存入其中,
判断控制电器的状态,判断电路是否通路,模拟各种情况,最后输出各个元件的状态。

其中串联电路类内部使用ArrayList类型保存每一个设备,最后确定没一个开关的状态,最后进行排序输出即可。

然后是这次题集的第三道题,首次接触到了集合类型,这道题是一道改错题,使用Collection c = new ArrayList();
保存每一个员工,使用迭代器遍历输出,难度也一般。

//主函数
public class Main {

    public static void main(String[] args) {
        // 1、创建有序集合对象
        Collection <Employee>c  = new ArrayList();
        Scanner sc = new Scanner(System.in);
        // 创建3个员工元素对象
        for (int i = 0; i < 3; i++) {

            String employeeName = sc.nextLine();
            int employeeAge = sc.nextInt();
             sc.nextLine();
            Employee employee = new Employee(employeeName, employeeAge);
            c.add(employee);
        }



        // 2、创建迭代器遍历集合
        Iterator <Employee>it=c.iterator();

        //3、遍历
        while (it.hasNext()) {

            //4、集合中对象未知,向下转型
            Employee e = (Employee) it.next();

            System.out.println(e.getName() + "---" + e.getAge());
        }
    }

这是Main方法部分,声明了一个迭代器it,接收集合c的迭代器,然后遍历。

踩坑心得:

(1) 这次的大作业难度不大,但是由于看漏了条件,导致最后有几个测试点一直没有通过,这道题允许开关多次出现,最后输出结果要排序。后来我就声明了一个ArrayList类型专门保存所有开关,只有一遇见开关,就将这开关对象存入,判断是否有开关存在,如果有就排序输出。同时开关类也实现了Comparable接口。

@Override
    public int compareTo(Switch o) {
        if (name.compareTo(o.getName()) < 0)
            return -1;
        else
            return 1;
    }

(2) 还有本次大作业的分档变速器是必须在0-3之间,不能炒出这个范围的,需要加上特判条件。

例如:

 else if(Line.contains("#F"))
            {
                if(Line.contains("+")&&gears<3)
                {
                    gears++;
                }
                else if(Line.contains("-")&&gears>0)
                {
                    gears--;
                }
            }

这样保证档位不会超出范围。

改进建议:

(1) 下一次迭代肯会将入并联电路,所以应将串联电路继承于电器设备类,这样方便下次迭代。

(2) 对于其他电路设备可以像对待开关一样操作,这次大作业说明了其余设备只出现一次,但是下次不一定,所以全部使用List泛型存储,在实现Comparable接口,方便排序。

以吊扇类为例:

 @Override
    public int compareTo(Fan o) {
        if(name.compareTo(o.getName())<0)
            return -1;
        else
            return 1;
    }
    if(D.size()!=0)
        {
            Collections.sort(D);
            for(int i=0;i< D.size();i++)
                D.get(i).display();
        }

这样所有电路设备多次出现排序的问题就可以解决。

第六次题集:

设计与分析:

这次大作业比起上次大作业多了一个并联电路,将并联电路视为一种特殊的电路元件即可,但同时也需要主要并联电路的电阻和电压的计算涉及到精度问他。以下是新的类图:

这次主要的增加的新类:

(1) 并联电路类(Parallel):继承电路设备类,也看成是一个独立的类。

以下是主要属性和方法:

class Parallel extends Equipment {

    private ArrayList<Series> seriesList;

    Parallel(ArrayList<Series> seriesList) {
        this.seriesList = new ArrayList<>();
        this.seriesList = seriesList;
    }

    @Override
    public void setVoltage(double c) {
        for(int i=0;i<seriesList.size();i++)
        {
            Series series=seriesList.get(i);
            if(series.IfPathway())
            {
                series.setVoltage(c);
                series.VoltageDivision();
            }
        }
    }


    @Override
    public boolean IfPathway()//检查并联是否通路
    {
        for(int i=0;i<seriesList.size();i++)
        {
            if(seriesList.get(i).IfPathway())
            {
                return true;
            }
        }
        return false;
    }

    @Override
    double getResistor() {
        for(int i=0;i<seriesList.size();i++)
        {
            if(seriesList.get(i).Ifshort())
            {
                return 0;
            }
        }
        double r = 0;
        double R = 0;
        for (int i = 0; i < seriesList.size(); i++) {
            Series s = seriesList.get(i);
            if(s.IfPathway())
            {
                R += (1.0 / s.getResistor());
            }
        }
        r =  (1.0 / R);
        return r;
    }


    @Override
    void display() {

    }

    @Override
    void close() {

    }
}

并联电路也是一个特殊的电路设备,所以他也有名字,电阻,电压。需要注意的是并联的电阻计算和电压的计算会有精度问题。

题干中说明了并联电路所包含的串联电路会在其之前输入,所以只要将每一条路(出了连接电源的串联)存在一起,创建并联电路时一起加入就行。

踩坑心得:

(1 )这道题涉及到并联电路电阻的计算,那么就肯定会出现一些,无限循环小数等非常规小数,导致计算结果出错。

例如:

输入:

#T1:[IN K1-1] [K1-2 D2-1] [D2-2 D3-1] [D3-2 OUT]
#T2:[IN K2-1] [K2-2 D1-1] [D1-2 OUT]
#M1:[T1 T2]
#T3:[VCC L1-1] [L1-2 M1-IN] [M1-OUT GND]
#K1
#K2
#L1:1.00
end

错误输出:

@K1:closed
@K2:closed
@L1:1.00
@D1:360
@D2:199
@D3:199

这是一个人标准错误的答案。

正确输出:

@K1:closed
@K2:closed
@L1:1.00
@D1:360
@D2:200
@D3:200

当D2的转速为199.99999时最后应输出200,而不是199。这是计算电压是,没有处理好。需要进行精度判断,如:

double TF=c1-Math.floor(c1);
        double TC=Math.ceil(c1)-c1;
        if(Math.min(TF,TC)<1e-10)
        {
            c1=Math.round(c1);
        }

这需要每次计算电压时加上这个判断即可AC。

改进建议:

​ 下次迭代是可能会加入并联电路串联的情况,所以在加入并联电路时需要进行遍历所有此前的串联,找到符合的串联,再加入并联电路中。为了应对各种迭代情况,所以类之间的耦合性一定要设法降低,不能导致牵一发而动全身,这样修改代码的工作量太大了。

总结:

对面向对象编程(OOP)概念理解加深了,Java是一种面向对象的语言,通过这三次作业,更深入地理解类、对象等概念。

然后代码组织与结构的能力增强,编写大型Java程序需要良好的代码组织和结构。

逐渐熟练如何使用接口、类组织代码,以及如何使用注释来提高代码的可读性。

调试能力提高,调试是开发过程中不可或缺的一部分。学会如何使用调试工具和技巧来定位和修复代码中的错误。

还精通了许多类的使用例如LinkList,ArraysList,HashMap等等。

然后是一些建议:
对于模拟家用电器控制系统可以在并联电路中加入一些特殊的元件,如电阻器,变压器等等,这样更符合实际情况。

之后的PTA作用可以加入一些算法数据结构的知识,促进我们自学,这几次作用都没有什么算法知识。

可以加入更多关联实际的题目,增强对面向对象的理解。

posted @ 2024-06-09 01:17  我超厉害的  阅读(5)  评论(0编辑  收藏  举报