OOP课程第三阶段总结Blog

OOP课程第三阶段总结Blog

 20201328-严振轩

  前言:学习OOP课程的第三阶段已经结束了,而OOP课程也已经接近尾声。本阶段的学习体现出敏捷式迭代编程学习的形式,作业与作业间有充分联系。以下是我对本阶段学习总结以及题目分析。

(1)题目集7作为本阶段的开篇,通过两道图形卡片游戏编程题目对前一阶段学习到的继承与多态进行了复习运用。以及学习到了ArrayList的使用方法,并通过此方法,对象的添加以及数据处理有了更为高效的运用。新的编程思路的运用在于:“开-闭”原则以及单一职责原则的运用,通过两道题目迭代,同时知识的更新使用,为后续题目集有了更多的编程思路启发。难度而言,通过率较高,属于新知识,易学,并通过老师给的类图,可以较为轻松完成作业。

 

 

 

 (2)题目集8题目量少,仅一道,难度却是不一样的大。因为这一次的需要我们通过ATM机业务背景自己去设计类间关系,题目本身逻辑简单,考察在实体类,业务类的设计,以及为后续迭代拓展,需要遵守编程的“开-闭原则”以及为将后续添加功能,需要做到设计严谨,对于自己拓展的类也需要遵守“单一职责原则”,总体而言是难度较大的一次作业,需要真正去自己动脑设计,而不是单纯的根据他人的类图编程。

 

 

 

 

(3)题目集9题量同样也为一道。题目形式也为ATM机类机构设计。本次添加了贷记以及透支取款的功能。本次作业是需要在老师提供的源码上进行功能添加以及本身源码的完善。进行了抽象类,多态,继承的运用。虽是之前就运用过的方式,本次需要我们主动去想到在什么方面进行使用。高质量符合题目要求的源码完成,需要对以上知识点有充分的认识与吸收。此题目本身功能性不复杂,需要我们去做到类的关系调用以及设计类功能是难度所在。

 

 

 

 

各题目  设计与分析  采坑心得  改进建议 :

 

(1)题目集7:(7-1)图形卡片排序游戏 (7-2)图形卡片分组游戏  递进式设计分析总结

 

设计与分析

7-1 类图以及复杂度分析图

 

 

 

 

 

 

 

7-2 类图以及复杂度分析图

 

 

     就7-1而言,本次为图形卡片排序游戏,通过设计出一个抽象Shape类,进而对Shape进行拓展出三角形,圆形,矩形,梯形类,其中在主类进行对象合法性的检验以及对应图形数量的添加。在不同的主体类中有着大致相同的方法:求面积,合法性校验,Set,Get方法,在DealCardList业务类中进行对对应具体图形类属性的添加,进而将实体类与业务类联系起来。实体类都继承于Shape类中。而在代码中设计了求面积的接口类,实现了求面积的多态。功能体现在对输入的图形进行求面积处理,其次进行了排序,最后求出面积总和。对于多对象情况,采用存在ArrayList中进行流水线式的处理,使代码更为简洁,不需要一个个判断后再进行添加。设计遵守了单一职责原则以及“开-闭”原则,便于7-2题目的拓展功能添加。

 

  就7-2而言,本次为图形卡片分组游戏,该次作业是对7-1题目的迭代,添加的功能有:对初始求出的面积数据进行分组;对分组后的数据在组内进行排序;得到全部图形中的最大面积。实体类设计与7-1无差别,主要使DealCardList业务类中,需要进行更为细致的分组处理。首先在DealCardList类中添加了几种Boolean型方法,判断语句采用了匹配字符串的equals语句,进行初步的分类校验。通过创建四种方法,将不同的四种图形的输出方式表示为一种长字符串进行输出,每确定一种图形的种类,以及算出对应面积之后,则将新确定的字符串拼接在之前的字符串后一位,以card顺序i作为循环上限,将每次i对应的图形一个个进行校验,以确定在对应输出位置上。排序方法上选择了插入排序,并且代码的循环语句采用的增强for循环。在求最大面积上,将card的i作为循环依据,通过比较得出最后的最大面积的值,本次作业难度不算大,但需要细致的类间关系调用,才会使代码更简洁可观。而对于ArrayList的使用同样也十分重要,对象的处理因此更为高效。

 

 采坑心得

7-1题目中代码:

 

 

 7-2题目中代码:

 

 

 

 

     7-2主类开始的代码中较7-1不同的地方是需要先进行一次开始输入的n是否是0的判断,在7-2测试点的要求中,需要对第一个n有特殊的判断,若一开始的n就为0,则需要直接结束程序并输出Worry Format。在一开始进行7-2代码编写时,并没有刻意注意这个问题,导致个别测试点无法通过,后通过测试找到了问题,并完成了代码补充。

 

public String Circle1() {
        String str = "";
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Circle"))
                str+="Circle:"+String.format("%.2f",i.getShape().getArea()) + " ";
        }
        return str;
    }
    public String Rectangle2() {
        String str = "";
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Rectangle"))
                str+="Rectangle:"+String.format("%.2f",i.getShape().getArea()) + " ";
        }
        return str;
    }
    
    public String Triangle3() {
        String str = "";
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Triangle"))
                str+="Triangle:"+String.format("%.2f",i.getShape().getArea()) + " ";
        }
        return str;
    }
    
    
    public String Trapezoid4() {
        String str = "";
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Trapezoid"))
            str+="Trapezoid:"+String.format("%.2f",i.getShape().getArea()) + " ";
        }
        return str;
    }

   

    该部分的代码是为后续分组的呈现所额外书写的。一开始对于分组的实现想的是通过遍历后对i对应的CardName进行equals检验字符串,再创建四钟List存储得到的分组结果。后发现该种思路的书写过于亢长且逻辑混乱,代码再eclipse中得到了正确结果,在PTA中因代码长度限制,从而更改了思路,直接采用四种方法遍历,去匹配到组别以及位置。

 

double max = 0;
        double sum = 0;
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Circle"))
            sum+= i.getShape().getArea();
        }
        if(sum > max) {
            max = sum;
        }
        sum = 0;
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Rectangle"))
            sum+= i.getShape().getArea();
        }
        if(sum > max) {
            max = sum;
        }
        sum = 0;
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Triangle"))
            sum+= i.getShape().getArea();
        }
        if(sum > max) {
            max = sum;
        }
        sum = 0;
        for(Card i:cardList) {
            if(i.getShape().getShapeName().equals("Trapezoid"))
            sum+= i.getShape().getArea();
        }
        if(sum > max) {
            max = sum;
        }
        sum = 0;
        System.out.print(String.format("%.2f",max));

 

    该部分代码为求面积和最大值的功能。初始设计时对于题目理解错误,认为是求单个图形的面积最大值,所写出的for循环更多,遍历的时间更长。后发现无法通过大多数的测试点,通过PTA测试点分析,得到是题目理解出了问题,删减了一部分代码后,添加的if语句找到了图形面积和最大值。并得到了对应的输出。

 

改进建议

1.改进点更多在类中方法的设计以及功能算法设计上。在7-1中,对于排序上采用的依旧是插入排序法,而也尝试过去使用sort排序,这样的代码更加的简洁有效。后发现使用后会无法得到结果,再完成了7-2后发现,我排序的对象的card里的i,而不是i对应的对象。所以若能将全部的排序规则改进为sort排序,则可以将代码更为简洁。

2.7-2中提出了新的要求:分组,分组后排序,组面积和最大值寻找。在7-2中对于新功能的添加,更多是通过if语句与for语句进行识别,再通过添加新的方法去实现。后通过进行题目集9中ATM机设计中认识拓展性并不是通过一昧的if与for循环进行添加功能,可以对每个实体类进行充分的利用,拓展。本次题目中的分组问题可以通过在每个实体类中便设定一种“标签”方法,标签方法有统一的接口,在分组的过程中,通过图形对象调用该方法去确定属于哪一类并只和同一种图形标签的对象输出在一个[]之中。

3.求组面积和的功能上,不需要如上述写的在分组之后,再重复遍历去求和,再进行组与组之间的比较。可以在分组的时候,便同时进行面积的加合,待全部的图形面积完成了对应的分组,也同时完成了面积和的运算。

4.对于面积和最大值的寻找,不需要再进行多次的for循环与if判断,再建议3的基础上,最后进行一次sort排序便能得到最大值,直接进行结果的输出。

 

递进式设计分析总结

    两次作业带来的感觉就是面向对象设计在添加功能上的技巧性与规范性十分重要。若为了添加功能反复的使用if语句以及for语句,则是面向过程编程的设计思路,虽然可以同样实现功能但是若数据庞大,则难以进行功能的添加与数据的处理。所以从迭代递进的设计来看,需要从初始属性,功能设计的开始就要遵循“开-闭”原则以及单一职责原则,为了类可以进行扩充,为了类单一定向功能的实现,使得后续维护或者功能添加有方向可找,不会盲目在业务类中进行方法的堆叠。在两次卡片游戏中,收获了对ArrayList存储对象并调用对象实现的方法的熟悉使用,不仅可以符合面向对象设计的原则,也可以在添加类功能上,完全进行适应,通过列表对象调用方法,可以高效可观的完成对应的任务。最多的是对类似于:排序法,基本语法,基本算法,对象创建,add方法等基础方法综合使用,成功的迭代是在原本代码的基础上做对应功能的添加,而不需要大面积更改,对此我仍需要学习如何真正践行“开-闭”原则。

 

 

(2)题目集8:(7-1)ATM机类结构设计(一) 题目集9:(7-1)ATM机类结构设计(二)  ATM机仿真题目的设计思路分析总结

 

设计与分析

7-1 类图以及复杂度分析图

 

 

 

 

 

7-2 类图以及复杂度分析图

 

 

 

 

   就题目集8的7-1而言,该题目用于设计一个简单的ATM机功能,功能作用在:简单的存取款与查询余额。设计的背景为:中国银联,中国银行,银行用户,银行账户,银行卡,ATM机。该背景的各个组成部分,都可以实现为一个实体类。各个实体类之间有一定的关联性,其中例如:各个中国银行组成了中国银联,而中国银行里有着不同的银行用户,银行用户拥有自己独立的银行账户,而银行账户通过银行卡进行操作,ATM机作为银行服务于用户的机器,联系着银行与账户等。需要设计出联系紧密且又实效的类间关系。实体类需要自己去考虑到类间的关系,而业务类则需要根据用户的需求设计不同的功能。例如实现不同输入情况下做到的存取款,以及查询余额的功能。我的代码在Verifcation类中作为业务类,在该类中完成不同的功能。在该类中首先构建了属于自己的数据储存库,保证调用对应账户或者银行卡号不会错乱,以及余额的每次更新都会得到改变。在主类中利用正则表达式对输入的情况进行不同的分支走向,比如通过空格分隔元素得到是存取款还是查询余额。后又会在Verifcation类进行不同的数据的校验:卡号,ATM编号,密码,金额合法,是否跨行。通过合法校验的数据则进行数据处理,通过依次对应的if语句,对输入结果进行完善,存取金额则是简单的加减法,只需要完成了输入内容的其他部分,直接调用存取金额的方法直接填入数据即可。最终输出是通过将一步一步的中间输出作为字符串存储在一个字符串数组之中,在主类的最后同一个for循环全部进行输出。以上是ATM机设计(一)的设计思路。

 

  就题目集9的7-1而言,本次的代码是在老师给的代码的基础上进行功能的添加与优化。考察的依旧是:继承,多态,抽象类,类间关系设计以及对于“开-闭”原则,单一职责原则的掌握。跟题目集8的7-1有所不同的是添加一种信用卡,可以进行贷记操作,以及银联有了超额度的服务费扣取功能,跨行收费。该功能的添加与对本身代码的优化修改是难点。难在不知在哪进行修改,不知如何添加在恰当位置,且易将本来具有简单功能的代码解构,难以保证质量。以下进行代码结果i有分析:首先用户数据的导入通过在主类里分别进行对用户信息,账户信息,银行卡,借记卡信息,以及ATM,银行,银联信息的添加,也就是利用add方法进行对象添加。以及进行双向绑定,将对象与对象之间的联系更为紧密,也方便进行调用。在该代码中,我设计了账户父类与卡父类,以下有借记账户子类,信用账户子类以及借记卡与信用卡的子类。通过构造统一的卡类,其中包含着两种子卡类,账户类同理。主类中依旧是根据正则表达式以及if语句决定功能走向的分支。对于新添加的透支与跨行的功能,分别将跨行利率作为对应银行的属性,将透支服务费收取金额的利率作为银联的属性。当判断需要收取对应费用时,可以直接调用对应的属性即可。例如在某ATM机上跨行取钱,则通ATM机号找到对应的银行,调用该银行的利率属性进行收费的计算。其中在功能计算中,通过instanceof方法对不同类别的账户进行不同的超出额度输出判断。本题需要额外考虑的有:跨行判断后跨行情况的收费处理,以及透支收费,剩余金额的实时更新以及更新后判断是否超出额度。这些都是在通过不同类负责不同的判断依据与功能操作得到的最后结果。最后的输出通过while循环实现。以上是ATM机设计(二)的设计思路。

 

 采坑心得

 

 

   该部分为判断取款金额是否大于余额的判断,以及对判断结果对应的数据处理。其中容易掉入的陷阱是,若金额已经达到了透支,则不适用money = amount的数据处理。一开始设计单纯的采用单一的数据处理,后测试点部分无法通过,进行了透支测试后发现了问题。

 

 

 

  该部分代码进行对账户的类型判断,进而对对应账户进行不同的账户余额检验,例如借记账户仅用考虑10000的上限,而信用账户拥有贷记的功能,有50000的透支上限,两类不同的余额检验需要分开进行判断。

 

 

   该部分为跨行处理后,需要在原本的金额上额外扣除跨行的额外收费,原本代码过于亢长,需要先得到ATM对应的银行,后计算得到需要额外缴付的跨行收费。而该一个if语句就足够完成跨行判断以及跨行收费的增加。

 

 

 

   对于类的设计来看,设计中有卡父类以及账户父类,以及往下分支:信用卡类,借记卡类,信用账户类,借记账户类;这样的设计符合继承,且处理起来符合多态,无需在主类刻意区分两种卡类,在数据处理中会在各自类中调用特有的方法进行功能的实现。起初未这样设计,代码亢长且难以对多数据进行处理,不符合继承与多态,更改了类的设计后,更具逻辑性与拓展性。

改进建议

 1.在判断是否是贷记账户类还是借记账户类上,这一步如可以不用进行类的判断,设计一个统一的接口进行同名方法处理,则更可体现出多态性。也延续了代码的可拓展性以及可维护性。

 2.业务类过于繁重,可以通过设计两个业务类,一是数据校验判断业务类,而是数据处理业务类,这样更可以体现出程序设计的单一职责原则。

 3.在账户之间设定可联系的类,可为后续设计转款功能作为基础,或是在数据处理类中添加方法去完成转款功能。

 

ATM机仿真题目的设计思路分析总结

 

 题目集8的7-1用于设计一个简单的ATM机功能,功能作用在:简单的存取款与查询余额。设计的背景为:中国银联,中国银行,银行用户,银行账户,银行卡,ATM机。该背景的各个组成部分,都可以实现为一个实体类。各个实体类之间有一定的关联性题目集9的7-1而言,本次的代码是在老师给的代码的基础上进行功能的添加与优化。考察的依旧是:继承,多态,抽象类,类间关系设计以及对于“开-闭”原则,单一职责原则的掌握。跟题目集8的7-1有所不同的是添加一种信用卡,可以进行贷记操作,以及银联有了超额度的服务费扣取功能,跨行收费。主类中都是根据正则表达式以及if语句决定功能走向的分支。不同点在于会在题目集9的代码中不同的银行添加不同的利率属性,在业务类中添加对跨行后的收费处理以及透支判断等。以上都是对特定功能的添加,需要考虑到类设计的“开-闭”原则,单一职责原则。以及迭代到的不仅是相同背景内容的功能添加,更有考虑到类间关系,去充分利用实体类的属性绑定以及方法调用。业务类中集成方法去实现最终输出的效果。本次ATM机迭代编程,本身逻辑层面简单,注重的是严谨的设计思想与正确的面向对象编程思维。

 

 

大总结

   本次阶段的三次作业,更多的是对所学类设计的应用,主要是对两种原则的掌握:“开-闭”原则,单一职责原则。以及对于“封装性,继承,多态,复用等”需要有自己的理解去很好的利用。对于设计的想法,面向对象设计的初衷在于将处理的事情对象化,对象要求什么功能,我们便需要去满足它。在这一阶段的学习中,对于作业难度并不是以往的设计好的算法去实现,前几次阶段的题目更像是套着面向对象的壳去用电脑完成数学题。这一阶段本身题目逻辑并不复杂,考察的是我们对于一个事物去实现,我们该如何去做的一个好的设计,设计围绕着可维护,可拓展,以及后续根据源码去添加功能,都在让我们学习并实际去运用着面向对象编程的设计思想。对于后续需要学习的界面设计,需要掌握JavaFx,为此也在进行相关的学习,不断学习,也在不断回顾学到的内容。并且会进行深度的挖掘,更好的去理解面向对象设计的内涵。

 再次感谢这一阶段的学习,即将进入尾声的面向对象设计的课程,学到了以面向对象的思想去进行程序设计,也是作为软件工程专业的入门基础。感谢老师与助教的工作,也要感谢坚持到现在的自己!自信的向下一阶段出发!

 

posted @ 2021-06-16 13:43  Yan7zx  阅读(129)  评论(1)    收藏  举报