题目集7-9的总结性blog
一、前言
题目集七
第七次题目集共有两道题目。其中第一题图形卡片排序游戏知识点主要是掌握类的继承、多态性使用方法以及接口的应用,第二题在第一题的基础上更加深入,需要考虑面向对象设计的“单一职责原则”,并且思考该程序是否能够符合“开-闭”原则。此次题目集难度偏中等,两道题目逐渐深入,第二题的难度要高于第一题,相较于第一题,第二题的输出更加复杂,需要对各个图形进行分组后排序输出他们的面积,而第一题不需要对图形进行分组,只需要直接对各个面积排序后输出。
题目集八
第八次题目集只有一道题目,但该题目难度较大,需要设计ATM仿真系统,能够完成用户的存款,取款以及查询余额的功能。这道题主要考核的是类的封装性以及类与类之间的关系设计。它的难度在于它的属性多,并且不同的属性之间都存在着关联和对应,需要设计各种实体类来分别对应数据,以及各种实体类之间的关系。由于是设计银行ATM的模拟程序,代码要有一定的灵活性,方便存入用户信息。
题目集九
第九次题目集在第八次题目集的基础上进行了深入。这次题目集也只有一道题目,需要设计ATM仿真系统,但是比第八次题目集增添了新的内容。和第八次题目集不同,这次题目集不止有借记卡,也加入了信用卡,用户可以使用信用卡贷款,并且能够进行跨行存取款,同时需要收取一定的跨行费用。这次题目集的难度更大,算法更加复杂,同时还新增加了几个用户的信息。
二、设计与分析
题目集七
7-1
本程序仅用于为学生所玩的游戏提供正确答案的功能,即根据学生得到的卡片种类与数量,给出 排序前和排序后的卡片顺序,同时给出所有卡片的面积之和。
参考类图:

首先判断无数据输入的情况
int num = in.nextInt(); if(num == 0) { System.out.println("The original list:"); System.out.println(); System.out.println("The sorted list:"); System.out.println(); System.out.printf("Sum of area:0.00"); System.exit(0); }
当输入数字不为0时判断输入是否合法后将数字加入list
while(num != 0) { if(num < 0 || num > 4) { System.out.println("Wrong Format"); System.exit(0); } list.add(num); num = in.nextInt(); }
shape类为父类
class Shape{ private static String shapeName; public Shape() { } public Shape(String shapeName) { this.shapeName = shapeName; } public static String getShapeName() { return shapeName; } public static void setShapeName(String shapeName) { Shape.shapeName = shapeName; } public static double getArea() { return 0.0; } public static boolean validate() { return true; } public String toString() { return getShapeName() + ":" + String.format("%.2f", getArea()); } }
圆形、矩形、三角形、梯形类都继承自shape类,圆形卡片需要输入圆的半径,矩形卡片需要输入矩形的宽和长,三角形卡片需要输入三角形的三条边长,梯形需要输入梯形的上底、下底以及高。
如三角形类,先创建构造方法,然后有getArea()方法获得图形的面积,validate()方法判断输入合法性:
class Trapezoid extends Shape{ private static double topSide; private static double bottomSide; private static double height; public Trapezoid() { } public Trapezoid(double topSide,double bottomSide,double height) { this.topSide = topSide; this.bottomSide = bottomSide; this.height = height; } public static double getArea() { return (topSide + bottomSide) * height / 2; } public static boolean validate() { if(topSide > 0 && bottomSide > 0 && height > 0) { return true; } else { return false; } } }
获取输入的各个图形的面积并存入areas[]中:
for(int i=0;i<list.size();i++) { if(list.get(i) == 1) { Circle cir = new Circle(Main.in.nextDouble()); if(cir.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Circle"; areas[i] = cir.getArea(); } else if(list.get(i) == 2) { Rectangle rect = new Rectangle(Main.in.nextDouble(),Main.in.nextDouble()); if(rect.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Rectangle"; areas[i] = rect.getArea(); } else if(list.get(i) == 3) { Triangle tri = new Triangle(Main.in.nextDouble(), Main.in.nextDouble(), Main.in.nextDouble()); if(tri.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Triangle"; areas[i] = tri.getArea(); } else if(list.get(i) == 4) { Trapezoid trap = new Trapezoid(Main.in.nextDouble(),Main.in.nextDouble(),Main.in.nextDouble()); if(trap.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Trapezoid"; areas[i] = trap.getArea(); } }
cardsort()方法用于对各个面积利用排序方法进行排序并按顺序输出:
public static void cardSort() { double[] areas1 = new double[areas.length]; int[] index = new int[areas.length]; for(int i=0;i<index.length;i++) { index[i] = i; } for(int i=0;i<areas.length;i++) { areas1[i] = areas[i]; } for(int i=0;i<areas1.length-1;i++) { int max = i; for(int j=i+1;j<areas1.length;j++) { if(areas1[j] > areas1[max]) { max = j; } } if(max != i) { double m = areas1[max]; areas1[max] = areas1[i]; areas1[i] = m; int n = index[max]; index[max] = index[i]; index[i] = n; } } for(int i=0;i<areas1.length;i++) { System.out.print(shapeName[index[i]]+":"+String.format("%.2f", areas1[i])+" "); } }
getAllArea()方法用于获取总面积和:
public static double getAllArea() { double allArea = 0; for(int i=0;i<areas.length;i++) { allArea += areas[i]; } return allArea; }
showResult()方法用于按条件输出所有的内容:
public static void showResult() { System.out.println("The original list:"); for (int i=0;i<shapeName.length;i++) { System.out.print(shapeName[i]+":"+String.format("%.2f", areas[i])+" "); } System.out.println(); System.out.println("The sorted list:"); cardSort(); System.out.println(); System.out.printf("Sum of area:%.2f\n",getAllArea()); }
7-2
本题沿袭作业7-1,本次作业主要对卡片(Card)进行分组游戏,其规则为随机发放一些卡片给学生, 卡片仍然分为四种形状:圆形(Circle)、矩形(Rectangle)、三角形(Triangle)及梯形(Trapezoid), 并给出各种卡片的相应参数,要求学生首先根据卡片类型将所有卡片进行分组(一个类型分为一组, 所以最多四组),然后能够对每组内的卡片根据面积值从大到小进行排序,同时求出该组内所有卡片 的面积之和,最后求出每组卡片面积之和中的最大值。图形类设计可参考作业 7-1 的类层次结构(需要进一步完善),本次作业要求对卡片排序时使用 Comparable 接口或 Comparator 接口。
代码类图如下:

本题主要在7-1的代码上做出了相应的改动。改变的地方主要在于DealCardList类,其他的地方几乎不变。
创建每个图形对应的数组,面积对应的数组,图形名称对应的数组:
static double[] circle = new double[Main.list.size()]; static double[] rectangle = new double[Main.list.size()]; static double[] triangle = new double[Main.list.size()]; static double[] trapezoid = new double[Main.list.size()]; static double[] areas = new double[Main.list.size()]; static String[] shapeName = new String[Main.list.size()];
将每一个数字对应的图形的面积和图形名称按顺序存入各个数组中:
for(int i=0;i<list.size();i++) { if(list.get(i) == 1) { j++; Circle cir = new Circle(Main.in.nextDouble()); if(cir.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Circle"; areas[i] = cir.getArea(); circle[j-1] = cir.getArea(); } else if(list.get(i) == 2) { k++; Rectangle rect = new Rectangle(Main.in.nextDouble(),Main.in.nextDouble()); if(rect.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Rectangle"; areas[i] = rect.getArea(); rectangle[k-1] = rect.getArea(); } else if(list.get(i) == 3) { l++; Triangle tri = new Triangle(Main.in.nextDouble(), Main.in.nextDouble(), Main.in.nextDouble()); if(tri.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Triangle"; areas[i] = tri.getArea(); triangle[l-1] = tri.getArea(); } else if(list.get(i) == 4) { p++; Trapezoid trap = new Trapezoid(Main.in.nextDouble(),Main.in.nextDouble(),Main.in.nextDouble()); if(trap.validate()==false) { System.out.println("Wrong Farmat"); System.exit(0); } shapeName[i] = "Trapezoid"; areas[i] = trap.getArea(); trapezoid[p-1] = trap.getArea(); } }
sort(double[] shape)方法用于对每个图形类型的面积进行排序:
public static void sort(double[] shape) { for(int i=1;i<shape.length;i++) { for(int j=0;j<shape.length-1;j++) { if(shape[j+1]>shape[j]) { double num = shape[j]; shape[j] = shape[j+1]; shape[j+1] = num; } } } }
cardSort()方法用于按顺序输出每种图形所有排序好的数据:
public static void cardSort() { System.out.print("["); if(j>0) { sort(circle); for (int i=0;i<j;i++) { System.out.print("Circle:"+String.format("%.2f", circle[i])+" "); } } System.out.print("]"); System.out.print("["); if(k>0) { sort(rectangle); for (int i=0;i<k;i++) { System.out.print("Rectangle:"+String.format("%.2f", rectangle[i])+" "); } } System.out.print("]"); System.out.print("["); if(l>0) { sort(triangle); for (int i=0;i<l;i++) { System.out.print("Triangle:"+String.format("%.2f", triangle[i])+" "); } } System.out.print("]"); System.out.print("["); if(p>0) { sort(trapezoid); for (int i=0;i<p;i++) { System.out.print("Trapezoid:"+String.format("%.2f", trapezoid[i])+" "); } } System.out.print("]"); }
getMaxArea()用来获取最大的面积和:
public static double getMaxArea() { double maxArea = 0; double area1 = 0,area2 = 0,area3 = 0,area4 = 0; if(j>0) { for(int i=0;i<j;i++) { area1 += circle[i]; } } if(k>0) { for(int i=0;i<k;i++) { area2 += rectangle[i]; } } if(l>0) { for(int i=0;i<l;i++) { area3 += triangle[i]; } } if(p>0) { for(int i=0;i<p;i++) { area4 += trapezoid[i]; } } if(area1>area2&&area1>area3&&area1>area4) { maxArea = area1; } else if(area2>area1&&area2>area3&&area2>area4) { maxArea = area2; } else if(area3>area2&&area3>area1&&area3>area4) { maxArea = area3; } else if(area4>area2&&area4>area3&&area4>area1) { maxArea = area4; } return maxArea; }
showResult()方法用于按条件输出所有的内容:
public static void showResult() { System.out.println("The original list:"); System.out.print("["); for (int i=0;i<shapeName.length;i++) { System.out.print(shapeName[i]+":"+String.format("%.2f", areas[i])+" "); } System.out.print("]"); System.out.println(); System.out.println("The Separated List:"); System.out.print("["); if(j>0) { for (int i=0;i<j;i++) { System.out.print("Circle:"+String.format("%.2f", circle[i])+" "); } } System.out.print("]"); System.out.print("["); if(k>0) { for (int i=0;i<k;i++) { System.out.print("Rectangle:"+String.format("%.2f", rectangle[i])+" "); } } System.out.print("]"); System.out.print("["); if(l>0) { for (int i=0;i<l;i++) { System.out.print("Triangle:"+String.format("%.2f", triangle[i])+" "); } } System.out.print("]"); System.out.print("["); if(p>0) { for (int i=0;i<p;i++) { System.out.print("Trapezoid:"+String.format("%.2f", trapezoid[i])+" "); } } System.out.print("]"); System.out.println(); System.out.println("The Separated sorted List:"); cardSort(); System.out.println(); System.out.printf("The max area:%.2f\n",getMaxArea()); } }
题目集八
本题要求编写一个银行 ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能。
代码类图如下:

首先输入用户ID,判断ID输入是否合法,输入密码并进行匹配,如果正确在输入剩余的用户信息并判断是否合法:
for(;ID.equals("#")==false;) { validateID(ID); password = in.next(); if(password.equals("#")) { Search search = new Search(ID); search.search(); System.exit(0); } String[] IDs = Card.setID(); int a=0; for(int i=0;i<10;i++) { if(password.equals(IDs[i])) { a = 1; } } if(a == 1) { Search search = new Search(ID); search.search(); ID = password; password = in.next(); } num = in.next(); money = in.next(); validateNum(num); validatePassword(password); validateBank(ID,num); if(money.charAt(0) == '-') { SaveMoney save = new SaveMoney(ID,password,num,money); save.save(); } else { validateBalance(ID,money); DrawMoney draw = new DrawMoney(ID,password,num,money); draw.draw(); } ID = in.next(); }
SaveMoney类用于执行存钱操作并输出相应的结果:
class SaveMoney{ private static String ID; private static String password; private static String num; private static String money; public SaveMoney() { } public SaveMoney(String ID,String password,String num,String money) { this.ID = ID; this.password = password; this.num = num; this.money = money; } public static void save(){ String name = Card.getName(ID); String bank = Card.getBank(name); int index = Card.getLastMoney(ID); money = money.substring(1); Main.lastMoney[index] = Main.lastMoney[index] + Double.parseDouble(money); System.out.println(name+"在"+bank+"的"+num+"号ATM机上存款¥"+money); System.out.println("当前余额为¥"+String.format("%.2f", Main.lastMoney[index])); } }
DrawMoney类用于执行取钱操作并输出相应的结果:
class DrawMoney{ private static String ID; private static String password; private static String num; private static String money; public DrawMoney() { } public DrawMoney(String ID,String password,String num,String money) { this.ID = ID; this.password = password; this.num = num; this.money = money; } public static void draw() { String name = Card.getName(ID); String bank = Card.getBank(name); int index = Card.getLastMoney(ID); Main.lastMoney[index] = Main.lastMoney[index] - Double.parseDouble(money); System.out.println(name+"在"+bank+"的"+num+"号ATM机上取款¥"+money); System.out.println("当前余额为¥"+String.format("%.2f", Main.lastMoney[index])); } }
Search类用于执行查询用户信息操作并输出相关内容:
class Search{ private static String ID; public Search() { } public Search(String ID) { this.ID = ID; } public static void search() { int index = Card.getLastMoney(ID); System.out.println("¥"+String.format("%.2f", Main.lastMoney[index])); } }
Card类用于记录用户的对应信息:
class Card{ public static String[] setID(){ String[] IDs = new String[10]; IDs[0] = "6217000010041315709";IDs[1] = "6217000010041315715"; IDs[2] = "6217000010041315718";IDs[3] = "6217000010051320007"; IDs[4] = "6222081502001312389";IDs[5] = "6222081502001312390"; IDs[6] = "6222081502001312399";IDs[7] = "6222081502001312400"; IDs[8] = "6222081502051320785";IDs[9] = "6222081502051320786"; return IDs; } public static String getName(String ID) { String[] IDs = setID(); if(ID.equals(IDs[0])||ID.equals(IDs[1])||ID.equals(IDs[2])) { return "杨过"; } else if(ID.equals(IDs[3])) { return "郭靖"; } else if(ID.equals(IDs[4])||ID.equals(IDs[5])||ID.equals(IDs[6])||ID.equals(IDs[7])) { return "张无忌"; } else if(ID.equals(IDs[8])||ID.equals(IDs[9])) { return "韦小宝"; } else { return ""; } } public static String getBank(String name) { if(name.equals("杨过")||name.equals("郭靖")) { return "中国建设银行"; } else { return "中国工商银行"; } } public static int getLastMoney(String ID) { String[] IDs = setID(); if(ID.equals(IDs[0])||ID.equals(IDs[1])) { return 0; } else if(ID.equals(IDs[2])) { return 1; } else if(ID.equals(IDs[3])) { return 2; } else if(ID.equals(IDs[4])) { return 3; } else if(ID.equals(IDs[5])) { return 4; } else if(ID.equals(IDs[6])||ID.equals(IDs[7])) { return 5; } else if(ID.equals(IDs[8])) { return 6; } else { return 7; } } }
题目集九
本题要求编写一个银行 ATM 机的模拟程序,能够完成用户的取款以及查询余额功能。但是本次作业中银行卡包含借记卡和信用卡两类,且允许跨行办理相关业 务(例如在中国建设银行的 ATM 机上使用中国工商银行的银行卡进行业务操作)。
代码类图如下:

本题是修改老师课上的代码,以下将给出我修改的内容。
添加的相关用户和银行信息:
Bank abc = new Bank("1003","中国农业银行",0.04); unionPay.addBank(abc); ATM aTM7 = new ATM("07",abc); ATM aTM8 = new ATM("08",abc); ATM aTM9 = new ATM("09",abc); ATM aTM10 = new ATM("10",abc); ATM aTM11 = new ATM("11",abc); abc.addATM(aTM7); abc.addATM(aTM8); abc.addATM(aTM9); abc.addATM(aTM10); abc.addATM(aTM11); User Zhangsanfeng = new User("","张三丰",""); User Linghuchong = new User("","令狐冲",""); User Qiaofeng = new User("","乔峰",""); User Hongqigong = new User("","洪七公",""); Account ccbAcc4 = new Account("3640000010045442002",10000.00,Zhangsanfeng,ccb,"credit"); Account icbcAcc6 = new Account("3640000010045441009",10000.00,Linghuchong,icbc,"credit"); Account abcAcc1 = new Account("3630000010033431001",10000.00,Qiaofeng,abc,"credit"); Account abcAcc2 = new Account("3630000010033431008",10000.00,Hongqigong,abc,"credit"); ccb.addAccount(ccbAcc4); icbc.addAccount(icbcAcc6); abc.addAccount(abcAcc1); abc.addAccount(abcAcc2); Zhangsanfeng.addAccount(ccbAcc4); Linghuchong.addAccount(icbcAcc6); Qiaofeng.addAccount(abcAcc1); Hongqigong.addAccount(abcAcc2); Card ccbCard11 = new Card("6640000010045442002","88888888",ccbAcc4); Card ccbCard12 = new Card("6640000010045442003","88888888",ccbAcc4); Card icbcCard13 = new Card("6640000010045441009","88888888",icbcAcc6); Card abcCard14 = new Card("6630000010033431001","88888888",abcAcc1); Card abcCard15 = new Card("6630000010033431008","88888888",abcAcc2); ccbAcc4.addCard(ccbCard11); ccbAcc4.addCard(ccbCard12); icbcAcc6.addCard(icbcCard13); abcAcc1.addCard(abcCard14); abcAcc2.addCard(abcCard15);
除此之外,给每个银行添加了对应的跨行取款的收费百分比:
Bank ccb = new Bank("1001","中国建设银行",0.02); Bank icbc = new Bank("1002","中国工商银行",0.03); Bank abc = new Bank("1003","中国农业银行",0.04);
修改的主要部分在WIthDraw类中
检测是否为跨行取款并且如果是则扣除相应的跨行取款费用:
double lastBalance = 0; if (account.getBank().getBankNO() != aTM.getBank().getBankNO()) { if(balance == amount && account.getType().equals("debit")) { System.out.println("Sorry,your account balance is insufficient."); System.exit(0); } lastBalance = balance - amount * aTM.getBank().getBankCharge() - amount; } else { lastBalance = balance - amount; } if(amount > balance) { if(balance >= 0) { lastBalance = lastBalance - (amount - balance) * 0.05; } else { lastBalance = lastBalance - amount * 0.05; } }
如果取款金额超出了余额则传入1,否则传入0:
if(amount > balance) { showResult(account,1); }else { showResult(account,0); }
如果传入的是1,先判断是否是信用卡再进行操作:
if(flag == 1) { if(account.getType().equals("debit")) { System.out.println("Sorry,your account balance is insufficient."); System.exit(0); } else if(account.getType().equals("credit")) { if(account.getBalance()<-50000) { System.out.println("Sorry,your account balance is insufficient."); System.exit(0); } else { System.out.println("业务:取款 "+userName + "在" + bankName + "的" + ATMID + "号ATM机上取款" + String.format("¥%.2f", amount)); System.out.println("当前余额为" + String.format("¥%.2f", account.getBalance())); } } }
如果传入的是0,进行相关操作:
else { System.out.println("业务:取款 "+userName + "在" + bankName + "的" + ATMID + "号ATM机上取款" + String.format("¥%.2f", amount)); System.out.println("当前余额为" + String.format("¥%.2f", account.getBalance())); }
其他的内容与老师给的代码大体相同。
三、采坑心得
在这三次题目集中,对源码的提交过程出现了许多问题,在解决问题的过程中本人也获得了许多心得。
在题目集七的7-1中,我忽略了只输入一种图形的情况,导致当只输入一种形状时程序输出“Wrong Format”,测试点三、四、五、六无法通过。

在题目集八中,我并没有考虑查询功能是可以在任何时候输入的,从而导致程序输出错误,测试点十二无法通过。


在题目集九中,借记卡是无法透支余额的,如果需要跨行则需要支付跨行手续费用,所以无法取出卡内所有余额,而我忽略了这一点。


通过这三次题目集,我意识到自己考虑问题依旧不够全面,容易忽略掉可能出现的情况而导致程序出现输出错误的现象,希望我在以后能够多多的考虑题目,让程序更加全面。
四、改进建议
经过这几次题目集,我对于面向对象程序设计这一课程的了解也逐渐深入。在题目集九的完成时,老师已经给出了题目集八的源码让我们根据题目集八的源码对代码进行改进来完成题目集九。我在对老师给出的源码研究时,意识到自己之前的代码的简单性,虽然完成了相关的功能,却没有任何的复用性,很难在我的代码的基础上进行改进完成题目集九。并且我的代码大部分都还停留在面向过程程序设计的思路中,对老师源码的研究时,我逐渐理解了面向对象程序设计的内容,对其有了更深的理解,也逐渐开始掌握其中的内容。
五、总结
这三次题目集难度偏中等,老师已经大幅度降低了题目的难度。在这一阶段中,我们主要学习了类的封装性以及类与类之间的关系设计,类的继承、多态性使用方法以及接口的应用。经过这几次练习,我们对类之间的关系有了更深的了解,并且更深的明白了对象的意义。以后我们可以在如何使代码更加简单,更加具有复用性深入。
随着课程的深入,老师也在听取学生们的意见,对题目量和题目难度进行了减轻,并且在题目集九直接给出了部分源码让我们只用对其进行相应的改进就可。所以对本课程的建议我现在暂无,认为老师已经尽量顾及到同学们的感受了。

浙公网安备 33010602011771号