总结性Blog3
一、前言
这三次PTA的题量较小,但题目难度却是中等偏上的水平,题目都非常有意思,每两道题目为一组,一组内的第二道题目都可以看作为对第一道题目的进阶、升级版,逐渐扩大我们对题目的熟悉感以及思考能力,不仅仅是完成作业,而是对题目进行举一反三进一步提高我们对代码的整体架构思考、构思。在Java课程进入尾声之际,对本学期的Java作业和所学的知识做一个总结。这个学期的Java作业确实对我的编程能力有了一定的锻炼,但同时也让我发现了我在学习上的许多不足。我在Java学习上还是以被动学习为主,完全靠老师平时布置作业进行练习。
作业过程总结:
① 总结作业之间的知识迭代关系:
一开始的作业,都只是对语法和算法的简单考察,基本上只有if,else if,或者switch的循环结构,最多只接触了Boolean类型,还都是偏面向过程的题目。到了后几次就开始是给Main类补充方法和类了,开始接触面向对象的思维了,再后来的几次都是在指导书给的类图的结构和Main类的引导下将题目解决完成。最后的几次作业不给指导书,让我们根据自己所学的,自由发挥,考察了我们总结独立去解决问题的能力。
②如何通过作业逐步理解面向对象的封装性、继承性与多态性三大技术特性:
最开始我们的作业很简单,通常一个Main类就可以解决,到了后来根据老师给的Main类和指导书,我们开始学会在老师的题设引领下对功能进行分装到类,学习了封装性。后来老师又给我们设计Shape类型的问题,通过让我们各种图形共有的比如,面积,周长,体积等特性,让我们使用继承来接解决实际问题,学习了继承性。后来的作业我们又开始接触了接口,一个类继承另一个类,然后又可以有不同的方法,所谓多态性。
二、设计与心得
题目集7(7-1)、(7-2)两道题目的递进式设计分析总结
图形卡片排序游戏
题目中给出了主要源码,并提供相应的类图。
public class Main { //在Main类中定义一个静态Scanner对象,这样在其它类中如果想要使用该对象进行输入,则直接 //使用Main.input.next…即可(避免采坑) public static Scanner input = new Scanner(System.in); public static void main(String[] args){ ArrayList<Integer> list = new ArrayList<Integer>(); int num = input.nextInt(); while(num != 0){ if(num < 0 || num > 4){ System.out.println("Wrong Format"); System.exit(0); } list.add(num); num = input.nextInt(); } DealCardList dealCardList = new DealCardList(list); if(!dealCardList.validate()){ System.out.println("Wrong Format"); System.exit(0);4 / 4 } dealCardList.showResult(); input.close(); } }

这在大体上给我们提供了一种解题思路,图形卡片游戏总共提供了4种卡片类型,分别为1代表圆形卡片,2代表矩形卡片,3代表三角形卡片,4代表梯形卡片。先构造Shape类,创造私有属性图形名称,该类里面包含三个抽象方法,分别为验证图形的合法性,获取图像的面积,以及打印图形的名称三种抽象方法,接着设计4个图形类,分别是Circle类、 Rectangle类、Triangle类、Trapezoid类,四个类继承Shape类,但是需要重写Shape类中的getArea、validate、toString三个方法。这几个方法在前面的作业的作业中都有提到。游戏要求根据第一行数字所代表的卡片图形类型,依次输入各图形的相关参数。一共是四种卡片,List<卡片> 卡组 = new ArrayList<>();然后通过ArrayList<Integer> list = new ArrayList<Integer>();使用switch(list.get(i))来控制构造不同的图形对象。如果图形数量非法(小于 0)或图形属性值非法(数值小于 0 以及三角形三边不能组成三 角形),则输出“Wrong Format”。然后就是排序问题了,排序前的各图形类型及面积,格式为图形名称1:面积值1图形名称2:面积值2 …图形名称n:面积值n ;排序后的各图形类型及面积,格式同排序前的输出,对卡片排序时使用 Comparable 接口, 即 Card 类需要实现 Comparable 接口中的 CompareTo()方法。比较两个图形的面积问题上我使用做差的方法来解决面积排序问题
class Card implements Comparable{ private Shape shape; public Card(){ } public Card(Shape shape) { this.shape = shape; } public Shape getShape() { return shape; } public void setShape(Shape shape) { this.shape = shape; } public int compareTo(Card card) { double value = shape.getArea()-card.getShape().getArea(); if(value<0) { return -1; }else if(value>0) { return 1; } return 0; } } interface Comparable { public int compareTo(Card card); }
这道题主要考察的是掌握类的继承、多态性使用方法以及接口的应用。这道题的难度不大。
第二道题目同样是图形卡片排序问题
在作业 7-1 的基础上进行进一步改进和完善。考虑面向对象设计的“单一职责原则”,思考该程序是否能够符合“开-闭”原则。
一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
用抽象构建框架,用实现扩展细节
优点:提高软件系统的可复用性及可维护性。
当代码需要额外扩展或者修改定制专有的功能时,应该提供一种抽象来扩展功能 而不是修改原代码。
这道题除了对各图形信息进行输入并输出;输入数据的正确性校验; 对输入的图形按照图形类型进行分组并输出,还需要满足对每组内的图形按照面积值降序排序并输出,求出每组内图形面积的总和,求出所有组的面积总和的最大值并输出。重点是在 ArrayList 工具类的使用;在面积比较上给一个list排序,我们这里用的是collections中的sort()方法,实体类中会重写比较方法。
public void cardSort() { Collections.sort(cardList,new Comparator<Card>() { public int compare(Card s1,Card s2) { if(s1.getShape().getArea()<s2.getShape().getArea()) return 1; else if(s1.getShape().getArea()>s2.getShape().getArea()) return -1; else return s1.toString().compareTo(s2.toString()); } }); } public double getmaxArea() { double a=0, b=0,c=0,d=0; for(int i=0;i<cardList.size();i++) { if(cardList.get(i).getShape().toString().equals("Circle:")) { a+=cardList.get(i).getShape().getArea(); } else if(cardList.get(i).getShape().toString().equals("Rectangle:")) { b+=cardList.get(i).getShape().getArea(); } else if(cardList.get(i).getShape().toString().equals("Triangle:")) { c+=cardList.get(i).getShape().getArea(); } else if(cardList.get(i).getShape().toString().equals("Trapezoid:")) { d+=cardList.get(i).getShape().getArea(); } } if(a>b&&a>c&&a>d) return a; else if(b>a&&b>c&&b>d) return b; else if(c>a&&c>b&&c>d) return c; else return d; }
题目的难度中等,可以看作为上道题目的进阶版,对此题目进行举一反三进一步提高我们对代码的整体架构思考、构思。
题目集8、题目9:
设计ATM仿真系统,编写一个银行 ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能。

根据题目给出的相关信息,分别设计银联类,银行类,银行用户类,银行账户类,银行卡类以及ATM机类。根据题目要求初始化两张表内的数据。这两次题目集中,一个用户在同一个银行可以有多个银行账号,且可以有多个隶属卡号,余额互通,典型的一对多实体类。第九次作业中银行卡包含借记卡和信用卡两类,且允许跨行办理相关业务,需要单独创建一个中国农业银行,此外,如果还要跨行取钱的话,就还需要额外付手续费,这个手续费每个银行标准都不一样,手续费默认均从银行卡所对应的账户中自动扣除。在老师提供的代码基础上进行改进,需要在账户类中添加一个新的卡的类型的变量,注意:初始化账户中也应该添加卡的类型,我设置int type = 1来作为判断该银行卡为阶级卡。在取款类中添加私有变量手续费,后面只需要获取卡的类型来进行判断是否需要手续费取款。最主要的思路是在银联中通过卡号,可以得到对应的账户,在银联中通过ATM机号,可以得到对应的归属银行,利用得到账户和归属银行进行存取款的操作。
三、踩坑心得
图形卡片类游戏中碰到的主要问题是Collection中的sort()方法,第一次写的时候没有弄清楚如何升序排序,如何降序排序导致在第一次检验时没有通过相关结点。ATM机仿真系统中碰到的主要问题是在输入数据后如何对数据进行分组处理,这时我想到前面的作业水文校验处理问题时发现可以使用StringBuilder方法来处理所有数据,将每行数据分组,再将每组的数据除去空格后对每个部分依次使用正则表达式将进行校验,更大的问题如何在设计时更好的实现题目中的各实体类之间的关系,尤其是一对多的组合关系。对实体类的设计要做到单一职责原则,且不能缺少规定的实体类。在“合成复用原则”及“单一职责原则”基础上,尽量对上次作业的程 序进行重构,使之符合 “开-闭”原则。
四、改进建议
对题目整体的设计上还是存在着很大的缺陷,比如说如何在设计时更好的实现题目中的各实体类之间的关系,尤其是一对多的组合关系。对实体类的设计要做到单一职责原则,且不能缺少规定的实体类。在“合成复用原则”及“单一职责原则”基础上,尽量对程序进行重构,使之符合 “开-闭”原则。除了严谨的思维外,对代码的测试也是代码质量的一个很好的保证。未通过测试点就是大家在一个个的测试后才发现的。所以多样化的测试点,是对代码运行结果的准确性和输出格式正确的一个很好的保障。保证数据的私有性,为了实现一个类的良好封装性,一定不要使用其他的方式去声明成员变量;对数据初始化,为了可读性,应该为变量提供初始化或是利用构造器进行初始化,局部变量必须初始化;一个类的功能尽量不要太繁杂,类名/方法名的名称要可以体现其职责,见名知意,增加代码可读性。
五、总结
总结Java学习的教训和经验:
通过这么长时间的对Java的学习,我对Java的许多基本概念都有了一个了解,和自己的认识。我通过作业逐步理解面向对象的封装性、继承性与多态性三大技术特性,还理解了“单一职责原则”和“ 开闭原则“,渐渐地从面向过程编程转向了面向对象编程。
① 对面向对象三大技术特性之间关系的理解:
在我个人目前看来,封装是通过将对象的某些属性和和操作隐藏起来,内部信息是对外隐藏的,在其他的地方就不能随便使用和调用了,是对方法成员的一种保护。封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。继承的子类可以拥有父类的公开属性、方法,子类可以拥有自己的属性和方法,即子类可以对父类进行扩展,子类可以用自己的方式实现父类的方法。Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类。多态是一种事物的不同表现形式,具有多样性。
② 面向对象设计的基本原则理解(单一职责原则及“开-闭”原则)编程思维的理解:
定义上来说:开闭原则(OCP)是面向对象设计中“可复用设计”的基石,开闭原则告诉我们应尽量通过扩展软件实体的行为来实现变化,而不是通过修改现有代码来完成变化,它是为软件实体的未来事件而制定的对现行开发设计进行约束的一个原则。我个人认为就是即每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。
③ 编程思维的理解:
我觉得就像面对对象这个概念一样,编程是面向使用者的,要将现实问题抽象成类,把不同的问题通过一个个类来解决掉。

浙公网安备 33010602011771号