面向对象程序设计——第三月课程小结
前言
不知不觉已经开始学习面向对象程序设计三个月了,先发一个小吐槽:老师总是在清明,劳动节,端午节前发布Blog作业,这让我感到有点小头疼。
    
老师还是挺好的,不是吗?
学了这么久面向对象程序设计,也做了有那么几道题目,感受到:面向对象和面向过程确实有很大的区别。就拿最近的一次PTA平台上的作业来说:做一个ATM机的模拟程序,如果说是让我面向过程程序设计的话,百八十行的代码就能把题目干玩,但使用面向对象的程序设计,我需要分析一个ATM对象的各种属性和特征,还有它背后的银行和使用它的用户的各种属性和特征。
就好像是面向过程程序设计是把难的问题逐步分解,拆成小问题,然后解决。
面向对象程序设计就像是把难的问题分析的很透彻,每一个类都思考清晰,然后在进行程序的编码。
分析问题感觉是所有学生的要害,总感觉我有哪里没想到,然后程序写得稀巴烂。
题目集07小结
题目集07 7-1 作业分析
又到了我最喜欢的图形卡片环节。
此题主要考察我对继承和多态的理解和某些接口的使用。(老师给的提示很隐晦,我后来查阅了资料才发现老师提到的接口是Collection接口)
          
就Comparable 这个接口我倒是没有用到,我只是在查阅资料发现Collection是一种集合的处理接口,它提供了很多方便对集合进行操作的方法,然后就用上了。
话不多说
题目要求输入一行数字,不同数字代表不同类型的图形卡片;在一行中输入每一个图形卡片的相应属性,比如:圆的属性就是半径,矩形的属性就是长和宽。
判断输入的属性是否规范这就不必我多说。
不过在面向对象的学习过程中,在做题时还是先会以面向过程思考问题的流程,然后再面向对象做类的设计,和框架的搭建。
代码设计
1.输入的一行数字(卡片类型)我可以用一个循环来获取,因为以“0”作为输入的结束。使用ArrayLIst储存获取到的卡片类型。
2.至于图形卡片的属性的输入,遍历这个储存了卡片类型数字的 list 来获取每一项到底是什么卡片。
3.在判断图形卡片类型的时候,我可以使用switch语句来进行判断。
         
4.老师已经给好了类图,创建了一个DealCardList类作为业务类。
代码编写
①首先倒还是按照老师给的类图设计,搭出一个代码的雏形。(其实很多的代码都是使用IDE自动生成的)
②卡片类型的数据输入:
         
没什么难度
        ③然后就在主类中创建DealCardList对象,使用构造方法的时候就将list作为参数传进去,然后它进行遍历,在遍历的过程中选择相应的卡片类型。
         
举一个梯形对象的例子,当原有的list中有了4,就分别输入上底、下底、高,然后再创建一个梯形对象。
CardList就添加一个Card对象(梯形对象为参数)
④数据传入程序之后,面积什么的我只需要调用对象中的getArea方法即可获得它面积。计算面积和判断属性数据是否有误算是比较简单的事了,不再详细叙述
        ⑤题目的难点是输出格式
The original list: ————可以遍历CardLIst链表输出每个元素的类名(名称)和它的面积,直接遍历即可。
          
The sorted list:————就需要我对链表按每一个元素的面积大小进行排序这里我是用了Collection接口来对链表的元素位置交换进行操作。
排序的原理是冒泡排序。
          
Collections的swap方法可以将集合中两个元素的位置进行对调,但是得先获取到它们的下标,所以就不使用foreach了。
计算总面积就是难题,直接遍历每一个list中的元素然后double一个sum加上去就行了。
度量分析
第一题倒还比较简单,稍微测了一下圈复杂度;
          
正好为5,还算符合原则。
题目集07 7-2 作业分析
这道题是 题目7-1的迭代进阶版,其实我还是觉得只改了输出的格式,但我还是在编写代码的时候把各种图形卡片分组的储存。
从其他方面上来看,类图和代码的实现难度似乎没变,也就是说,如果我第一题写的足够好,那么我第二题就可以少写代码。
代码设计
和上一题思路一样,但是我在DealCardList这个类中的showResult方法进行了重构修改。
首先要做到分组,我可以先遍历已经生成了的卡片链表,然后通过查找卡片的名字来进行分组。
分完组后就进行求面积的计算和相应的输出即可(题目还要求计算每一组的总面积,这个我认为就是在对各组的链表进行遍历就各组的总面积)。
开闭原则就可以用上了,我只要修改showResult方法。
代码编写
根据思路,对已经获得到的图形卡片进行分组
        
这样就给它们分号组了,接下来调用求总面积的方法
          public void getSum(ArrayList<Card> list){
                    double sum = 0;
                    for(Card i : list){
                          sum = i.getShape().getArea() + sum;
                    }
                    sumArea.add(sum);
             }
这样就可以得到一个含有每组总面积的链表
        
然后就需要搞定输出问题,要做到分组输出,我可以直接遍历刚刚分完组后的链表然后输出即可
        我重新写了一个方法,将这四个链表传进去然后分别输出                
这样就做到了分组输出。
度量分析
先测复杂度
          
差一点就超过10了,自从某天的java课后,我都以10复杂度为一个规范(虽然说我目前还是有很多题目的复杂度超过了10。
把类图画出来:
          
题目集07小结
两道有关图形卡片排序的题目,让我对抽象类的理解更加深刻。
在我的理解中:
抽象就是从多个事物中将共性的,本质的内容抽取出来。
多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,
那么只有功能声明,没有功能主体的 方法称为抽象方法。
这是我对抽象类和抽象方法的资料查阅。大概也就是说,抽象类是将多个对象的共同点抽出来成立一个类,这些共同点包括(字段,方法),
也就是所说的公共的、共同的属性和行为。把这些抽象出来。
题目集08
ATM机类结构设计(一)作业分析
在一开始拿到这道题的时候,我心想:ATM的模拟功能不就是余额的增删改查、加减乘除之类的操作,不禁让我想起了当初做课设的场景,也是对文本文件里的数据做一些增删改查。
但打开了作业的指导书,我才发现没有我想到的那么简单。头一次体会到《软件工程》科目的魅力,在开发软件的时候需要了解这个软件的业务背景
用户需求。然后根据需求来实现相应的功能和通过测试工程师的测试。
作业指导书里老师把需求写好了,测试数据也写好了,让我做一个ATM的模拟程序。
          
存取款的话,也就是看控制台输入的取款金额的正负性,正取款,负存钱(看老师给的输出样例可以看到)。那么可以得到存取款的公式:余额 - 取款金额。
代码设计
仍然是一道对数据的增删改查,那么我需要考虑好数据的存储结构。目前来说还没有学到Java文件的相关内容,所有的初始化数据全部存于内存之中。在Java里面
也有很多集合类方便我做数据的存储。
考虑到:一家银行可以有多个用户;一个用户可以拥有多个账户;一个账户可以办理多张银行卡;所以我选择使用Map类来进行数据的存储,就可以这样设计:一个
Key对应一个Value,然而Key是不可重复的,就像把银行作为一个Value,然后多个用户作为它的Key,这样就做到了一对多的储存结构。
理论存在。
               
在Bank类中创建了两个HushMap对象用于存 账户->用户,卡号->账户,这样的关系。一个链表用于存这个银行所拥有的ATM机,每一个ATM机都有一个所在银行
的银行名字。
            
数据的存储就是这样,那么如何根据一个卡号来查询它所在账户的余额并进行修改呢?
我把所有银行都放在一个银联类UnionPay中,然后把所有的HushMap添加进去,通过卡号作为它的Key,即可获取卡号->账户Map,然后获取这个作为Value账户,对这个查到的账户在进行查余额,存取款之类的操作。
代码编写(核心)
1.输入:
获取输入,按照输入格式,所有的输入样例以"#"号结尾,那么符号之前的所有字符串都要获取。在这里我使用了StringBuilder类来获取输入的字符串。
            
在每一行的末尾尾追一个“\n”,这样我可以在在字符串中对每一行进行一个区分。也就是说可以使用split("\n")方法对字符串进行分组,然后就获取到了每一行的 输入数据。
其实在每一行中,数据都是以空白进行分隔,那么我可再对每一行进行一个区分String[] strings1 = i.split("\\s+");
            
根据指导书要求,只输入卡号的时候,需要显示它的账户余额,所以我加了一个判断,因为是以空白进行分组,分完组后,单独输入的卡号它的数组大小就为1。
使用一个判断语句来进行不同的操作。
因为传进来的做处理的是一个字符串数组,所以我需要将这个字符串数组再拆开,以便我获取卡号、密码、取款金额和ATM机的编号。但这也是按顺序输入进来 的,所以只要获取数组的各个元素就行,使用split方法拆开这个字符串数组
接下来就需要实现存取款的功能了,把在Bank类中创建的有关卡号和账号联系的HushMap根据Value转化为数组,然后遍历这个数组判断原有的卡号是否与输入 进来的卡号相匹配。
            
调用set方法,得到余额然后做减法就可以对账户中的余额进行修改达到存取款的功能。对于一些错误输入的一些我就不在博客里多讲。
度量分析
在IDEA这个IDE上的圈复杂度分析可以知道圈复杂度为6,其实也并没有很多复杂的代码语句,无非就是利用循环遍历Map来获取数据。
          
类图
          
题目集08小结
此题ATM机的设计与以往不同,老师给出了多个对象,同时这些对象又有相应的属性。相互之间有有着不同的羁绊。
但其实是逐层包含的关系,就比如银联里有多个银行,银行里有多个用户,用户也可以拥有多个账户。但这之间有一个一一对应的关系(有点像映射)
所以我使用了Map类集合作为突破点,使得多张银行卡对应同一个账户,多个账户对应同一个用户。
写一个存取款的难度确实不大,我觉得这题的主要难度就是将指导书给的数据找一个合适的集合存起来,然后再根据输入的数据进行比对和修改。
在找这个合适的集合上,我花费了不少时间。其实,在我现在的知识储备中我熟悉的集合差不多就是数组,List一类的链表和有着一一对应关系的Map类。
找到了Map集合,我还得为此设计储存结构,实现这些一一对应的关系,我给出的方式是银行中拥有这些Map集合,用户就只需要有账户就行了,根本
不需要关注这些账户在哪家银行,我只要有账户就行了,账户的银行名是可以忽略的。所以我是将Map集合和List集合混用的。
我只能说这道题并不没有想象中的那么难,难的还是设计。
题目集09
ATM机类结构设计(二)作业分析
与题目集08的题目类似,但增加了跨行取款的功能并且还需要在取款的时候收手续费的功能。
一开始拿到这道题,我觉得这些功能并不难实现,再加上老师已经给了源码,在IDEA这样强大的IDE的情况下,我相信我能很快完成这次作业。
但是这次作业与我的预期并不相符,因为借记卡和信用卡的加入使得类设计变得更加复杂,但我认为可以将这两个类继承与原来的Account类。
这样就可以实现基本的功能。
           
跨行取款的功能只需要对账户所在银行的的名字进行比对即可,然后判断这个账户的类型,获取它的额度,信用卡它的初始额度就是为50000,借记卡的额度就是0.
代码设计
从指导书中给的数据来看,增加了一个农业银行,但这并没有太大的影响。
        
主要的改动就是增加了两个子类给Account类,然后在初始化数据的时候多态化。
在完成取钱的过程中,我可以通过卡号找到相应的账户,但是找到的账户是一个Account类,所以我写了一个判断去给它使用子类创建。
对于取钱收手续费的过程,我认为是取多少钱就要收相应的手续费,然后如果发生了透支取款,那么透支的部分就需要收透支的手续费。
代码编写
通过判断获得的账户类型然后再进行存取款的操作的
          
在Account类中增加了一个type的属性来区分账户的类型。
然后在取款的过程中需要收取手续费,各家银行的手续费比例不一样。
          
这样就完成了取款收手续费的操作,其实就是一个余额的set和get的问题分了三种情况讨论。
      在进行透支取款的时候,需要明白,当余额为0之后的取款才算透支(这个我想了好久)       
当余额小于0后,进行的取款操作都是需要收取取款的手续费和透支的手续费,gap是我设计的一个差距(是余额与取款金额的差值的绝对值),gap用来判断是否进行了透支
在这种情况下,gap就是透支的金额,所以也就是gap * 0.05的原因。
度量分析
先给出类图。
       
最大圈复杂度为14,在代码中写了太多的if语句用来判断账户的类型和银行种类。
没有达到小于10的预期,代码还能再次重构。
                                
题目集09小结
在本次题目集中,我认为还有所不足,因为我选择使用判断账户的类型来进行取款的操作,我觉得这并不能体现Java多态的特点。
不过在面向对象程序设计中,可复用性是很重要的,这道题我就是在老师给的代码基础上进行重构,老师的代码写的比我上次的要精简不少
复用性很强我觉得就是体现在别人用你代码的是侯不需要改太多地方就能实现更多的功能。
总结
在第三月的面向对象程序设计学习中,主要学习了多态和继承的用法。
      在很多时候我选择了使用一个抽象类作为一个父类,将子类较多数的共同点写入父类之中,然后再进行重写或者调用可以使代码更精简和易懂。
ATM这个例子也很生动。在此月的学习中我也顺便学习了如何高效的重构别人的代码,改成自己的。
希望以后能更好的面向对象。
 
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号