第三次Blog作业
一、前言
这三次题目集的题量比较少,但是难度比较大,每道题都要花不少时间来完成框架的构思,主要在于类的设计,用类的多态,继承,封装等设计各个类之间的关系,下面逐一来分析每道题设计的知识点。
(1)题目集7
7-1.图形卡片排序游戏
该题主要考察的是类的设计和接口的使用,要求掌握类的继承,多态和接口的实现技术,算法上涉及到了排序算法,知识点上涉及了ArrayList动态数组的使用,同时要实现Comparable接口中compare To()方法,考察了面向对象设计的单一,开闭原则。
7-2.图形卡片分组游戏
该题与7.1图形卡片排序游戏考察的知识点差不多,主要多加了个利用Comparable接口中的方法实现根据面积对卡片排序的功能,这里不多赘述。
(2)题目集8
7-1.ATM机类结构设计(一)
该题主要考察类的封装性及类间关系设计(关联、组合及依赖),对实体类要做到相应的单一设计原则,并且要求类之间关系或类的功能等设计完后具有可拓展性。
(3)题目集9
7-1.ATM机类结构设计(二)
该题在题目集8ATM机类结构设计(一)的基础上考察如何设计抽象类,用继承和多态对类的关系进行设计,在“合成复用原则”及“单一职责原则”基础上,使之符合“开-闭”原则。
二、设计与分析
①题目集7(7-1)、(7-2)两道题目的递进式设计分析总结
题目集7(7-1)类图:

题目集7(7-2)类图:

分析:从类图上来看,题目集7(7-1)和题目集7(7-2)的类图相差不大,其中Main类、Shape类、Rectangle类、Triangle类、Circle类、Trapezoid类完全一样,类的属性和方法都没有改变,主要差距在于DealCardList类中,不难发现,7-2的DealCardList类中属性更多,方法也多了(这里插一句,接口的变化可以忽略,其实两个题的接口的实现可以不变,当时做完7-1的时候发现Comparable接口是自带的,可以直接使用,无需重新定义,后面7-2改了,同时发现可以利用Collections类中的sort()方法直接对面积的大小进行排序),从这两个题目的递进式设计可以充分体现代码的复用性,以及代码的可拓展性。从类的属性和方法上观察,可以发现每个类都有每个类的特定功能,比如getArea()方法,每个继承Shape类的子类都进行了重写,用以获得各自的面积,体现了设计的“单一职责”原则,一个类/接口只执行一个职责。忽略接口的变化,7-1到7-2的最大区别在于7-2的DealCardList类在7-1的基础上增加了属性和方法,这体现了设计的“开-闭”原则,对扩展开放,对修改关闭。
②题目集8和题目集9两道ATM机仿真题目的设计思路分析总结
题目集8(7-1)类图:
设计思路分析:根据业务说明,先构建六个实体类,ChinaUnionPay类、Bank类、User类、Account类、Card类、ATM类,这六个类都有其特定的属性(比如Card类有卡号cardnumber,卡密码cardpassword属性)和方法,在设计上实现"单一职责"原则,然后使用ArrayList将各个类进行连接,使两个类之间实现一对多的关系,完成类间关系的设计。由于题目给了一些基础数据,因此我再设计了一个DataInitialization类,对这些数据进行存储,考虑到对于设计的可拓展性,我们只需要在DataInitialization类的bankdata()方法和userdata()方法中增加相应数据的代码即可。关于数据的检测,设计了一个CheckData类,里面有各种方法,比如检验卡号的CheckCardnumber()方法,在设计上又体现"单一职责"原则。
题目集9(7-1)类图:


设计思路分析:此次题目是在老师给的题目集8的源码上进行重构设计的,在设计上可以发现Card类有个Account属性,这样的好处是可以根据卡号找到账户,实现了从小到大的查询。设计前对源码的部分代码进行了重构,比如检验数据的方法全部放在ValidateData类中,使之符合单一职责原则。由于题目加了个可以跨行取款的操作,使账户有借记账户和贷记账户之分,卡有借记卡和信用卡之分,因此加了DebitAccount类、CreditAccount类、DebitCard类、CreditCard类,又由于这两个账户和这两个卡的属性和方法不需要重新再写,因此使这两个账户继承原来的Account类,这两种卡继承原来的Card类即可。不难发现,与题目集8的类图相比,也多了个GetBalance类和Withdraw类,在题目集8中我将这两个类放进了ATM类中使之成为方法使用,而在这单独拎出来作为一个类也是有可以的。
三、踩坑心得
1.关于ArrayList类型排序的使用
在题目集7(7-1)中,由于当时未发现Collection中的sort()方法,导致在对图形排序时,混合使用了简单的冒泡排序法和Comparable中的compare To()方法,使代码繁琐,在题目集7(7-2)中发现写好了Comparable中的compare To()方法后,可以直接用Collections对图形进行排序,两种方法对比如下:
public void cardsort() {//法一 for (int i = 0;i < this.cardList.size(); i++) { for (int j = 1;j < this.cardList.size(); j++) { if (this.cardList.get(j-1).compareTo(this.cardList.get(j)) == 1) { Card temp = this.cardList.get(j-1); this.cardList.set(j-1, this.cardList.get(j)); this.cardList.set(j, temp); } } } } public void cardsort() {//法二 Collections.sort(this.cardList); }
不难发现,使用Collections.sort()方法更加简单。
2.关于类的组合关系从小到大的查询
在题目集8的设计上,由于银联ChinaUnionPay中有多个银行Bank,银行Bank中有多个账户Account,多个用户User,多个ATM机ATM,用户User里面有多个账户Account,账户Account里面有多个卡号Card,各个类之间大都是一对多的组合关系,在ArrayList的使用下,从账户Account很容易找到各种卡号Card,那么如何根据卡号Card找到账号Account呢?在借鉴老师给的源码中发现了原来可以直接在Card类中定义一个Account account属性,然后在数据初始化卡号的时候,使用带Account的构造方法构造卡即可,利用getAccount()方法找到相应的账户,代码如下:
class Card { private Account account = null; public Card(String cardNO, String cardPassword, Account account) {//带Account的构造方法 super(); this.cardNO = cardNO; this.cardPassword = cardPassword; this.account = account; } public Account getAccount() {//得到卡号所在的账户 return account; } ... }
示例如下:
Card ccbCard1 = new DebitCard("6217000010041315709","88888888",ccbAcc1); Card ccbCard2 = new DebitCard("6217000010041315715","88888888",ccbAcc1); Card ccbCard3 = new DebitCard("6217000010041315718","88888888",ccbAcc2); Card ccbCard4 = new DebitCard("6217000010051320007","88888888",ccbAcc3);
这样我们就能够从Card找到Account了,其他的从ATM找到Bank等类似。
四、改进建议
1.关于代码运行效率的改进
在这些题目集中,很多题目我都使用了简单而传统的for语句(int i = 0; i < xxx;i++),后面通过学习对比发现,这种最简单的for语句在遍历数据时耗时比较长,就目前我所学会的几种遍历方式中,增强for语句的耗时比较短,以后尽量使用增强for语句,同样,在不同的代码中也要改变相应的方法,在ArrayList中用for,在LinkedList中用迭代器Iterator。
2.关于多余代码的改进
在题目集9中,老师给的源码有一部分的数据是不需要的,与题目无关,可以去掉,当时写的时候比较直接,没有去删掉这部分代码,比如User类中含有Phone这个属性,可以删去,减少运行时间,提高代码运行效率,从这我们可以思考,平时写代码时也需要注意不要写一些多余无关的代码,我们应该根据需要来写。
五、总结
从这三次题目集中学会了如何去设计一个类,先思考这个类的属性,作用等,再用封装,继承,多态技术去设计多个需要的类,在设计类之间的关系时,注意他们之间的关系(组合,依赖,关联等),也可以定义抽象类,利用抽象类中可能有抽象方法的特点,实现类型隐藏技术(因为继承的子类实现这个抽象方法时有很多种情况)。也可以利用接口实现多态性,提高程序的拓展性和可维护性。在设计代码的过程中,要学会运用面向对象的思想去设计一个程序,考虑"单一职责"原则、"开放封闭"原则、"Liskov替换原则"原则。
最近几次上课,老师讲解了一下ATM机的示例,对我们写代码还是有很大的帮助的,学会了一些设计程序的思想。关于作业,难度不是很大,建议可以混搭式出题,可以出一些我们早前作业不曾涉及到的知识点作为小题目,让我们去自学更多新的知识点,这样收获就会最大化了。

浙公网安备 33010602011771号