PTA题目集7-9的总结与归纳
PTA题目集7-9的总结与归纳
前言:总结三次题目集的知识点、题量、难度等情况
题目集7包含两道题:7-1 图形卡片排序游戏 ,7-2 图形卡片分组游戏 单从题目名字来看就已经很类似,所以用到的方法也就大同小异了。题目要求都有掌握类的继承、多态性使用方法以及接口的应用。难度不算太大,会了第一题,第二题即可在1的基础上做修改即可。
题目集8包含一道题:ATM机类结构设计(一)是ATM机系列的第一个层次,后面还有(二)(三)。从要求来看:编写一个银行 ATM 机的模拟程序,能够完成用户的存款、取款以及查询余额功能。(1)务必注意本题目中的各实体类之间的关系,尤其是一对多的组合关系。 (2)对实体类的设计要做到单一职责原则,且不能缺少规定的实体类。 (3)编程时考虑面向对象中的封装性本题目中的应用以及是否有能够扩展 的衍生需求。难度上了一个新台阶。
题目集9包含一道题: ATM机类结构设计(二) 是ATM机系列的第二个层次,在(一)的基础上增加了需要实现的功能。设计要求在(一)的基础上增加: (3)在“合成复用原则”及“单一职责原则”基础上,尽量对上次作业的程 序进行重构,使之符合 “开-闭”原则。难度逐级递增。
目录:
1.7-1 图形卡片排序游戏
2.7-2 图形卡片分组游戏
3.ATM机类结构设计(一)
4. ATM机类结构设计(二)
(一)7-1 图形卡片排序游戏
输入格式:
- 首先,在一行上输入一串数字(1~4,整数),其中,1代表圆形卡片,2代表矩形卡片,3代表三角形卡片,4代表梯形卡片。各数字之间以一个或多个空格分隔,以“0”结束。例如:
1 3 4 2 1 3 4 2 1 3 0 - 然后根据第一行数字所代表的卡片图形类型,依次输入各图形的相关参数,例如:圆形卡片需要输入圆的半径,矩形卡片需要输入矩形的宽和长,三角形卡片需要输入三角形的三条边长,梯形需要输入梯形的上底、下底以及高。各数据之间用一个或多个空格分隔。
输出格式:
- 如果图形数量非法(小于0)或图形属性值非法(数值小于0以及三角形三边不能组成三角形),则输出
Wrong Format。 - 如果输入合法,则正常输出,所有数值计算后均保留小数点后两位即可。输出内容如下:
- 排序前的各图形类型及面积,格式为
图形名称1:面积值1图形名称2:面积值2 …图形名称n:面积值n,注意,各图形输出之间用空格分开,且输出最后存在一个用于分隔的空格; - 排序后的各图形类型及面积,格式同排序前的输出;
- 所有图形的面积总和,格式为
Sum of area:总面积值。
首先得明白一道题的设计结构,类与类之间的关系:

这里Shape作为图形的父类,具体类Circle,Rectangle,Triangle,Traperoid继承父类;
DealCardList用于处理数据的一个类,有一个Arraylist装card类型,Card类中有Shape类型的卡片;
代码如下:
1 import java.util.ArrayList; 2 import java.util.Collections; 3 import java.util.Scanner; 4 5 public class Main { 6 //在Main类中定义一个静态Scanner对象,这样在其它类中如果想要使用该对象进行输入,则直接 7 //使用Main.input.next…即可(避免采坑) 8 public static Scanner input = new Scanner(System.in); 9 public static void main(String[] args){ 10 ArrayList<Integer> list = new ArrayList<Integer>(); 11 int num = input.nextInt(); 12 while(num != 0){ 13 if(num < 0 || num > 4){ 14 System.out.println("Wrong Format"); 15 System.exit(0); 16 } 17 list.add(num); 18 num = input.nextInt(); 19 } 20 DealCardList dealCardList = new DealCardList(list); 21 if(!dealCardList.validate()){ 22 System.out.println("Wrong Format"); 23 System.exit(0); 24 } 25 dealCardList.showResult(); 26 input.close(); 27 } 28 } 29 class Card{ 30 Shape shape; 31 Card(){ 32 33 } 34 Card(Shape shape){ 35 this.shape=shape; 36 } 37 public Shape getShape() { 38 return shape; 39 } 40 public void setShape(Shape Shape) { 41 this.shape=shape; 42 } 43 44 } 45 class DealCardList{ 46 ArrayList<Card> cardList=new ArrayList<Card>(); 47 DealCardList(){ 48 49 } 50 DealCardList(ArrayList<Integer> list){ 51 for(int i=0;i<list.size();i++) 52 { 53 if(list.get(i)==1) 54 { 55 double r=Main.input.nextDouble(); 56 Circle circle=new Circle(r); 57 Card card=new Card(circle); 58 card.getShape().setShapeName("Circle"); 59 cardList.add(card); 60 } 61 if(list.get(i)==2) { 62 double a=Main.input.nextDouble(); 63 double b=Main.input.nextDouble(); 64 Rectangle rectangle=new Rectangle(a,b); 65 Card card=new Card(rectangle); 66 card.getShape().setShapeName("Rectangle"); 67 cardList.add(card); 68 } 69 if(list.get(i)==3) { 70 double a=Main.input.nextDouble(); 71 double b=Main.input.nextDouble(); 72 double c=Main.input.nextDouble(); 73 Triangle triangle=new Triangle(a,b,c); 74 Card card=new Card(triangle); 75 card.getShape().setShapeName("Triangle"); 76 cardList.add(card); 77 } 78 if(list.get(i)==4) { 79 double a=Main.input.nextDouble(); 80 double b=Main.input.nextDouble(); 81 double c=Main.input.nextDouble(); 82 Traperoid traperoid=new Traperoid(a,b,c); 83 Card card=new Card(traperoid); 84 card.getShape().setShapeName("Trapezoid"); 85 cardList.add(card); 86 } 87 } 88 } 89 public boolean validate() { 90 for(int i=0;i<cardList.size();i++) 91 {if(!cardList.get(i).getShape().vaildate()) 92 return false;} 93 return true; 94 } 95 public void cardSort() { 96 for(int k=0;k<cardList.size();k++) 97 for(int i=k+1;i<cardList.size();i++) 98 { 99 if(cardList.get(k).getShape().getArea()<cardList.get(i).getShape().getArea()) 100 Collections.swap(cardList, k, i); 101 } 102 103 104 } 105 public double getAllArea() { 106 double s=0; 107 for(int i=0;i<cardList.size();i++) 108 s=s+cardList.get(i).getShape().getArea(); 109 return s; 110 } 111 public void showResult() { 112 System.out.println("The original list:"); 113 for(int i=0;i<cardList.size();i++) 114 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 115 System.out.println(); 116 System.out.println("The sorted list:"); 117 cardSort(); 118 for(int i=0;i<cardList.size();i++) 119 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 120 System.out.println(); 121 System.out.println("Sum of area:"+String.format("%.2f",getAllArea())); 122 } 123 } 124 class Shape { 125 private String shapeName; 126 Shape(){ 127 128 } 129 Shape(String shapeName){ 130 this.shapeName=shapeName; 131 } 132 public String getShapeName() { 133 return shapeName; 134 } 135 public void setShapeName(String shapeName) { 136 this.shapeName=shapeName; 137 } 138 public double getArea() { 139 return 0.0; 140 } 141 public boolean vaildate() { 142 return true; 143 } 144 145 } 146 class Circle extends Shape{ 147 private double radius; 148 Circle(){ 149 150 } 151 Circle(double radius){ 152 this.radius=radius; 153 } 154 public double getArea() { 155 return Math.PI*radius*radius; 156 } 157 public boolean vaildate() { 158 if(radius>0) 159 return true; 160 else return false; 161 } 162 } 163 class Rectangle extends Shape{ 164 private double width,length; 165 Rectangle (double width,double length){ 166 this.width=width; 167 this.length=length; 168 } 169 public double getArea() { 170 return width*length; 171 } 172 public boolean vaildate() { 173 if(width>0&&length>0) 174 return true; 175 else return false; 176 } 177 178 } 179 class Triangle extends Shape{ 180 double side1,side2,side3; 181 Triangle(double side1,double side2,double side3){ 182 this.side1=side1; 183 this.side2=side2; 184 this.side3=side3; 185 } 186 public double getArea() { 187 double c=(side1+side2+side3)/2; 188 double s=Math.sqrt(c*(c-side1)*(c-side2)*(c-side3)); 189 return s; 190 } 191 public boolean vaildate() { 192 if(side1+side2>side3&&side1+side3>side2&&side2+side3>side1) 193 return true; 194 else 195 return false; 196 } 197 198 199 } 200 class Traperoid extends Shape{ 201 private double topSide,bottomSide,height; 202 Traperoid(){ 203 204 } 205 Traperoid(double topSide,double bottomSide,double height){ 206 this.bottomSide=bottomSide; 207 this.height=height; 208 this.topSide=topSide; 209 } 210 public double getArea() { 211 return (topSide+bottomSide)*height/2; 212 } 213 public boolean validate() { 214 if(topSide>0&&bottomSide>0&&height>0) 215 return true; 216 else return false; 217 } 218 }
这里单拿出DealCardList类做分析:
45 class DealCardList{
46 ArrayList<Card> cardList=new ArrayList<Card>();
47 DealCardList(){
48
49 }
50 DealCardList(ArrayList<Integer> list){
51 for(int i=0;i<list.size();i++)
52 {
53 if(list.get(i)==1)
54 {
55 double r=Main.input.nextDouble();
56 Circle circle=new Circle(r);
57 Card card=new Card(circle);
58 card.getShape().setShapeName("Circle");
59 cardList.add(card);
60 }
61 if(list.get(i)==2) {
62 double a=Main.input.nextDouble();
63 double b=Main.input.nextDouble();
64 Rectangle rectangle=new Rectangle(a,b);
65 Card card=new Card(rectangle);
66 card.getShape().setShapeName("Rectangle");
67 cardList.add(card);
68 }
69 if(list.get(i)==3) {
70 double a=Main.input.nextDouble();
71 double b=Main.input.nextDouble();
72 double c=Main.input.nextDouble();
73 Triangle triangle=new Triangle(a,b,c);
74 Card card=new Card(triangle);
75 card.getShape().setShapeName("Triangle");
76 cardList.add(card);
77 }
78 if(list.get(i)==4) {
79 double a=Main.input.nextDouble();
80 double b=Main.input.nextDouble();
81 double c=Main.input.nextDouble();
82 Traperoid traperoid=new Traperoid(a,b,c);
83 Card card=new Card(traperoid);
84 card.getShape().setShapeName("Trapezoid");
85 cardList.add(card);
86 }
87 }
88 }
89 public boolean validate() {
90 for(int i=0;i<cardList.size();i++)
91 {if(!cardList.get(i).getShape().vaildate())
92 return false;}
93 return true;
94 }
95 public void cardSort() {
96 for(int k=0;k<cardList.size();k++)
97 for(int i=k+1;i<cardList.size();i++)
98 {
99 if(cardList.get(k).getShape().getArea()<cardList.get(i).getShape().getArea())
100 Collections.swap(cardList, k, i);
101 }
102
103
104 }
105 public double getAllArea() {
106 double s=0;
107 for(int i=0;i<cardList.size();i++)
108 s=s+cardList.get(i).getShape().getArea();
109 return s;
110 }
111 public void showResult() {
112 System.out.println("The original list:");
113 for(int i=0;i<cardList.size();i++)
114 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" ");
115 System.out.println();
116 System.out.println("The sorted list:");
117 cardSort();
118 for(int i=0;i<cardList.size();i++)
119 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" ");
120 System.out.println();
121 System.out.println("Sum of area:"+String.format("%.2f",getAllArea()));
122 }
123 }
124 class Shape {
125 private String shapeName;
126 Shape(){
127
128 }
129 Shape(String shapeName){
130 this.shapeName=shapeName;
131 }
132 public String getShapeName() {
133 return shapeName;
134 }
135 public void setShapeName(String shapeName) {
136 this.shapeName=shapeName;
137 }
138 public double getArea() {
139 return 0.0;
140 }
141 public boolean vaildate() {
142 return true;
143 }
144
145 }
这里的ArrayList<Integer> list是用于记录用户输入的图形类型,用循环来依次遍历,
用一个输入样例和输出样例作为参考:
输入样例2:
在这里给出一组输入。例如:
4 2 1 3 0 3.2 2.5 0.4 2.3 1.4 5.6 2.3 4.2 3.5
输出样例2:
在这里给出相应的输出。例如:
The original list: Trapezoid:1.14 Rectangle:3.22 Circle:98.52 Triangle:4.02 The sorted list: Circle:98.52 Triangle:4.02 Rectangle:3.22 Trapezoid:1.14 Sum of area:106.91
注意:
ArrayList<Integer> list中装的则是4 2 1 3 ,for循环遍历用if或者switch都可进行相应的判断。值得注意的一点是0不会存在
ArrayList<Integer> list中,在主函数中
if(!dealCardList.validate()){
System.out.println("Wrong Format");
System.exit(0);
}
如果第一个输入的为零,链表大小为0程序退出,最后一个输入0,
list.add(num);
num = input.nextInt();
添加数据在输入之前,为0则退出循环,执行不到添加0的操作。
(二)2.7-2 图形卡片分组游戏
输入格式:
- 在一行上输入一串数字(1~4,整数),其中,1代表圆形卡片,2代表矩形卡片,3代表三角形卡片,4代表梯形卡片。各数字之间以一个或多个空格分隔,以“0”结束。例如:
1 3 4 2 1 3 4 2 1 3 0 - 根据第一行数字所代表的卡片图形类型,依次输入各图形的相关参数,例如:圆形卡片需要输入圆的半径,矩形卡片需要输入矩形的宽和长,三角形卡片需要输入三角形的三条边长,梯形需要输入梯形的上底、下底以及高。各数据之间用一个或多个空格分隔。
输出格式:
- 如果图形数量非法(<=0)或图形属性值非法(数值<0以及三角形三边不能组成三角形),则输出
Wrong Format。 - 如果输入合法,则正常输出,所有数值计算后均保留小数点后两位即可。输出内容如下:
- 排序前的各图形类型及面积,格式为
[图形名称1:面积值1图形名称2:面积值2 …图形名称n:面积值n ],注意,各图形输出之间用空格分开,且输出最后存在一个用于分隔的空格,在结束符“]”之前; - 输出分组后的图形类型及面积,格式为
[圆形分组各图形类型及面积][矩形分组各图形类型及面积][三角形分组各图形类型及面积][梯形分组各图形类型及面积],各组内格式为图形名称:面积值。按照“Circle、Rectangle、Triangle、Trapezoid”的顺序依次输出; - 各组内图形排序后的各图形类型及面积,格式同排序前各组图形的输出;
- 各组中面积之和的最大值输出,格式为
The max area:面积值。
可以与上题作类比
输入样例3:
在这里给出一组输入。例如:
2 1 2 1 1 3 3 4 4 1 1 1 2 1 0
2.3 3.5 2.5 4.5 2.1 2.6 8.5 3.2 3.1 3.6 8.5 7.5 9.1245 6.5 3.4 10.2 11.2 11.6 15.4 5.8 2.13 6.2011 2.5 6.4 18.65
输出样例3:
在这里给出相应的输出。例如:
The original list: [Rectangle:8.05 Circle:19.63 Rectangle:9.45 Circle:21.24 Circle:226.98 Triangle:4.65 Triangle:29.80 Trapezoid:50.49 Trapezoid:175.56 Circle:105.68 Circle:14.25 Circle:120.81 Rectangle:16.00 Circle:1092.72 ] The Separated List: [Circle:19.63 Circle:21.24 Circle:226.98 Circle:105.68 Circle:14.25 Circle:120.81 Circle:1092.72 ][Rectangle:8.05 Rectangle:9.45 Rectangle:16.00 ][Triangle:4.65 Triangle:29.80 ][Trapezoid:50.49 Trapezoid:175.56 ] The Separated sorted List: [Circle:1092.72 Circle:226.98 Circle:120.81 Circle:105.68 Circle:21.24 Circle:19.63 Circle:14.25 ][Rectangle:16.00 Rectangle:9.45 Rectangle:8.05 ][Triangle:29.80 Triangle:4.65 ][Trapezoid:175.56 Trapezoid:50.49 ] The max area:1601.31
可以清楚地看到这道题与上一题的区别在于,将每种类型的图形分在了一起,并且按照图形的面积从大到小进行排序。
有了明确的目的之后,我们可以直接拿上一题的代码进行改进和完善。因此在这里我们只需要将输出的结果格式改一下即可达到目的。
重改Card里的showResult方法:
1 public void showResult() { 2 System.out.println("The original list:"); 3 System.out.print("["); 4 for(int i=0;i<cardList.size();i++) { 5 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 6 } 7 System.out.print("]"); 8 System.out.println(); 9 10 System.out.println("The Separated List:"); 11 12 System.out.print("["); 13 for (int i=0;i<cardList.size();i++){ 14 if (cardList.get(i).getShape().getShapeName().equals("Circle")){ 15 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 16 } 17 } 18 System.out.print("]"); 19 20 System.out.print("["); 21 for (int i=0;i<cardList.size();i++){ 22 if (cardList.get(i).getShape().getShapeName().equals("Rectangle")){ 23 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 24 } 25 } 26 System.out.print("]"); 27 28 System.out.print("["); 29 for (int i=0;i<cardList.size();i++){ 30 if (cardList.get(i).getShape().getShapeName().equals("Triangle")){ 31 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 32 } 33 } 34 System.out.print("]"); 35 36 System.out.print("["); 37 for (int i=0;i<cardList.size();i++){ 38 if (cardList.get(i).getShape().getShapeName().equals("Trapezoid")){ 39 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 40 } 41 } 42 System.out.print("]"); 43 System.out.println(); 44 45 System.out.println("The Separated sorted List:"); 46 47 48 49 cardSort(); 50 System.out.print("["); 51 for (int i=0;i<cardList.size();i++){ 52 if (cardList.get(i).getShape().getShapeName().equals("Circle")){ 53 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 54 } 55 } 56 System.out.print("]"); 57 58 System.out.print("["); 59 for (int i=0;i<cardList.size();i++){ 60 if (cardList.get(i).getShape().getShapeName().equals("Rectangle")){ 61 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 62 } 63 } 64 System.out.print("]"); 65 66 System.out.print("["); 67 for (int i=0;i<cardList.size();i++){ 68 if (cardList.get(i).getShape().getShapeName().equals("Triangle")){ 69 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 70 } 71 } 72 System.out.print("]"); 73 74 System.out.print("["); 75 for (int i=0;i<cardList.size();i++){ 76 if (cardList.get(i).getShape().getShapeName().equals("Trapezoid")){ 77 System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" "); 78 } 79 } 80 System.out.print("]"); 81 System.out.println(); 82 83 System.out.println("The max area:"+String.format("%.2f",getMaxArea())); 84 } 85 }
注意一个点:排序这里是在所有的card形状排好序后,再根据判断条件顺序输出的,不是将同形状归为一类后在进行排序。排序的代码:
public void cardSort() {
for(int k=0;k<cardList.size();k++) {
for(int i=k+1;i<cardList.size();i++)
{
if(cardList.get(k).getShape().getArea()<cardList.get(i).getShape().getArea()) {
Collections.swap(cardList, k, i);
}
}
}
}
(三)(四)ATM机类结构设计(一),(二)
面对一道全新的题时我们首先明确的应该是有哪些类,类与类之间的结构是怎么样的。
我们先理清ATM机系统有哪些关系:
⚫中国银联(China UnionPay)
⚫银行(Bank)
⚫银行用户(User)
⚫银行账户(Account)
⚫银行卡(Card)
⚫ ATM(Automated Teller Machine)
ATM机(一)中的要求:限定银行卡均为借记卡(不能透支),且不允 许跨行办理相关业务(例如在中国建设银行的 ATM 机上对其他银行的账户进行操 作)。
输入格式:每一行输入一次业务操作,可以输入多行,最终以字符#终止。
具体每种业 务操作输入格式如下: ➢ 存款、取款功能输入数据格式 卡号 密码 ATM 机编号 金额(由一个或多个空格分隔)
其中,当金额大于 0 时,代表取款,否则代表存款。 ➢ 查询余额功能输入数据格式 卡号
2)输出规则
①输入错误处理
如果输入卡号不存在,则输出“Sorry,this card does not exist.”。
如果输入 ATM 机编号不存在,则输出“Sorry,the ATM's id is wrong.”。
如果输入银行卡密码错误,则输出“Sorry,your password is wrong.”。
如果输入取款金额大于账户余额,则输出“Sorry,your account balance is insufficient.”。
如果检测为跨行存取款,则输出“Sorry,cross-bank withdrawal is not supported.”。
样例:
输入示例 3: 6217000010041315715 #
输出示例 3: ¥10000.00
输入示例 4: 6222081502001312390 88888888 06 -500.00
6222081502051320786 88888888 06 1200.00
6217000010041315715 88888888 02 1500.00
6217000010041315709 88888888 02 3500.00
6217000010041315715
#
输出示例 4: 张无忌在中国工商银行的 06 号 ATM 机上存款¥500.00
当前余额为¥10500.00
韦小宝在中国工商银行的 06 号 ATM 机上取款¥1200.00
当前余额为¥8800.00
杨过在中国建设银行的 02 号 ATM 机上取款¥1500.00
当前余额为¥8500.00
杨过在中国建设银行的 02 号 ATM 机上取款¥3500.00
当前余额为¥5000.00
¥5000.00
而ATM机(二)中的要求:本次作业中银行卡包含借记卡和信用卡两类,且允许跨行办理相关业 务(例如在中国建设银行的 ATM 机上使用中国工商银行的银行卡进行业务操作)。
业务假定
1)系统的测试用例均采用如上数据,且所有卡号密码默认为“88888888”, 初始余额均为 10000 元。
2)手续费默认均从银行卡所对应的账户中自动扣除。
3)跨行业务手续费收取比例由 ATM 机隶属银行决定,例如,用户手持中国 工商银行的银行卡在中国建设银行的 ATM 上进行取款操作,则手续费收取比例为 中国建设银行的相应比例,按初始化数据中的规定为取款金额的 2%。
4)跨行查询余额不收取手续费。
5)透支取款手续费由中国银联统一规定为 5%,最大透支金额均为 50000 元。
上图ATM(一):
下图:ATM(二)
增加了跨行取款的服务,同时跨行取款收取一定的手续费。在银行卡和账户上面,比原有的借记卡增加了贷记卡,增加了贷记账户。
上图ATM(一):

下图ATM(二):

主要的UML类图:


ATM(二)的一些测试样例:
输入样例5:
在这里给出一组输入。例如:
6640000010045442002 88888888 09 3000
6640000010045442002 88888888 06 8000
6640000010045442003 88888888 01 10000
6640000010045442002
#
输出样例5:
在这里给出相应的输出。例如:
业务:取款 张三丰在中国农业银行的09号ATM机上取款¥3000.00
当前余额为¥6880.00
业务:取款 张三丰在中国工商银行的06号ATM机上取款¥8000.00
当前余额为¥-1416.00
业务:取款 张三丰在中国建设银行的01号ATM机上取款¥10000.00
当前余额为¥-11916.00
业务:查询余额 ¥-11916.00
输入样例3:
在这里给出一组输入。例如:
6217000010041315715
#
输出样例3:
在这里给出相应的输出。例如:
业务:查询余额 ¥10000.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 账户抽象类
*
* @author Administrator
* @date
*/
abstract class AbstractAccount {
private String accountNO;// 账号
private double balance = 0;// 余额
private User user = null;// 用户
private Bank bank = null;// 所属银行
private double ratio = 0;// 透支取款手续费
private double overdrawAmount = 0;// 可透支金额
private static ArrayList<Card> list = new ArrayList<Card>();
public AbstractAccount() {
super();
// TODO Auto-generated constructor stub
}
public AbstractAccount(String accountNO, double balance, User user, Bank bank, double ratio,
double overdrawAmount) {
super();
this.accountNO = accountNO;
this.balance = balance;
this.user = user;
this.bank = bank;
this.ratio = ratio;
this.overdrawAmount = overdrawAmount;
}
public String getAccountNO() {
return accountNO;
}
public void setAccountNO(String accountNO) {
this.accountNO = accountNO;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public double getOverdrawAmount() {
return overdrawAmount;
}
public void setOverdrawAmount(double overdrawAmount) {
this.overdrawAmount = overdrawAmount;
}
public Bank getBank() {
return bank;
}
public void setBank(Bank bank) {
this.bank = bank;
}
public double getRatio() {
return ratio;
}
public void setRatio(double ratio) {
this.ratio = ratio;
}
public static ArrayList<Card> getList() {
return list;
}
public static void setList(ArrayList<Card> list) {
AbstractAccount.list = list;
}
public void addCard(Card card) {
list.add(card);
}
public void removeCard(Card card) {
list.remove(card);
}
}
/**
* ATM机类
*
* @author Administrator
* @date
*/
class ATM {
private String ATMID;
private Bank bank = null;// ATM所隶属银行
public ATM() {
super();
// TODO Auto-generated constructor stub
}
public ATM(String aTMID, Bank bank) {
super();
ATMID = aTMID;
this.bank = bank;
}
public String getATMID() {
return ATMID;
}
public void setATMID(String aTMID) {
ATMID = aTMID;
}
public Bank getBank() {
return bank;
}
public void setBank(Bank bank) {
this.bank = bank;
}
}
/**
* 工具类,和上次程序不同处之一,希望大家思考下该类的作用
*
* @author Administrator
* @date
*/
class ATMUtil {
/**
* 根据卡号获取银行卡,卡号正确则返回卡对象,否则返回null
*
* @param unionPay
* @param cardNO
* @return
*/
public static Card getCardbyCardNO(UnionPay unionPay, String cardNO) {
Card card = null;
Iterator<Bank> bankItr = unionPay.getBankList().iterator();
while (bankItr.hasNext()) {
ArrayList<AbstractAccount> accountList = bankItr.next().getAccountList();
Iterator<AbstractAccount> accountItr = accountList.iterator();
while (accountItr.hasNext()) {
ArrayList<Card> cardList = accountItr.next().getList();
Iterator<Card> cardItr = cardList.iterator();
while (cardItr.hasNext()) {
card = cardItr.next();
if (card.getCardNO().equals(cardNO)) {
return card;
}
}
}
}
return null;
}
/**
* 根据ATM ID求得ATM对象,如果ID正确则返回ATM对象,否则返回null
*
* @param unionPay
* @param ATMID
* @return
*/
public static ATM getATMbyATMID(UnionPay unionPay, String ATMID) {
Iterator<Bank> bankItr = unionPay.getBankList().iterator();
Bank bank = null;
ATM aTM = null;
while (bankItr.hasNext()) {
bank = bankItr.next();
Iterator<ATM> aTMItr = bank.getATMList().iterator();
while (aTMItr.hasNext()) {
aTM = aTMItr.next();
if (aTM.getATMID().equals(ATMID)) {
return aTM;
}
}
}
return null;
}
/**
* 根据卡号获取改卡所隶属的账号,若卡号正确,则返回账号对象,否则返回null
*
* @param cardNO
* @return
*/
public static AbstractAccount getAccountbyCardNO(String cardNO) {
Iterator<Card> cardItr = AbstractAccount.getList().iterator();
Card card = null;
while (cardItr.hasNext()) {
card = cardItr.next();
if (card.getCardNO().equals(cardNO)) {
return card.getAccount();
}
}
return null;
}
}
/**
* 银行类
*
* @author Administrator
* @date
*/
class Bank {
private String bankNO;// 银行编号
private String bankName;// 银行名称
private double commission;// 跨行业务收取的手续费
// 银行拥有的账户列表
private ArrayList<AbstractAccount> accountList = new ArrayList<AbstractAccount>();
// 银行拥有的ATM机列表
private ArrayList<ATM> ATMList = new ArrayList<ATM>();
public Bank() {
super();
// TODO Auto-generated constructor stub
}
public Bank(String bankNO, String bankName, double commission) {
super();
this.bankNO = bankNO;
this.bankName = bankName;
this.commission = commission;
}
public String getBankNO() {
return bankNO;
}
public void setBankNO(String bankNO) {
this.bankNO = bankNO;
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
public double getCommission() {
return commission;
}
public void setCommission(double commission) {
this.commission = commission;
}
public void addAccount(AbstractAccount account) {
this.accountList.add(account);
}
public void removeAccount(AbstractAccount account) {
this.accountList.remove(account);
}
public void addATM(ATM aTM) {
this.ATMList.add(aTM);
}
public void removeATM(ATM aTM) {
this.ATMList.remove(aTM);
}
public ArrayList<AbstractAccount> getAccountList() {
return accountList;
}
public void setAccountList(ArrayList<AbstractAccount> accountList) {
this.accountList = accountList;
}
public ArrayList<ATM> getATMList() {
return ATMList;
}
public void setATMList(ArrayList<ATM> aTMList) {
ATMList = aTMList;
}
}
/**
* 银行卡类,大家思考下该类与账户类的关系,例如用户的余额为什么不是设置在Card类中
*
* @author Administrator
* @date
*/
class Card {
private String cardNO;// 卡号
private String cardPassword;// 密码
private AbstractAccount account = null;// 该卡所属账号
public Card() {
super();
// TODO Auto-generated constructor stub
}
public Card(String cardNO, String cardPassword, AbstractAccount account) {
super();
this.cardNO = cardNO;
this.cardPassword = cardPassword;
this.account = account;
}
public String getCardNO() {
return cardNO;
}
public void setCardNO(String cardNO) {
this.cardNO = cardNO;
}
public String getCardPassword() {
return cardPassword;
}
public AbstractAccount getAccount() {
return account;
}
public void setAccount(AbstractAccount account) {
this.account = account;
}
public void setCardPassword(String cardPassword) {
this.cardPassword = cardPassword;
}
public boolean checkCard() {
Pattern p = Pattern.compile("\\d{16}+");
Matcher m = p.matcher(this.cardNO);
return m.matches();
}
public boolean checkPassword(String password) {
return this.cardPassword.equals(password);
}
}
/**
* 信用卡类,继承自抽象账户类
*
* @author Administrator
* @date
*/
class CreditAccount extends AbstractAccount {
public CreditAccount() {// 贷记账户
super();
// TODO Auto-generated constructor stub
this.setRatio(0.05);
}
public CreditAccount(String accountNO, double balance, User user, Bank bank, double ratio, double overdrawAmount) {
super(accountNO, balance, user, bank, 0.05, 50000.00);// 这是取巧但并不好的一种设计,大家思考下
// TODO Auto-generated constructor stub
}
}
/**
* 借记卡类,继承自抽象账户类
*
* @author Administrator
* @date 2021/06/12
*/
class DebitAccount extends AbstractAccount {// 借记账户
public DebitAccount() {
super();
this.setRatio(0);
// TODO Auto-generated constructor stub
}
public DebitAccount(String accountNO, double balance, User user, Bank bank, double ratio, double overdrawAmount) {
super(accountNO, balance, user, bank, 0, 0.00);// 同信用卡类的设计
// TODO Auto-generated constructor stub
}
}
/**
* 业务类,查询余额
*
* @author Administrator
* @date
*/
class GetBalance {
private UnionPay unionPay;// UnionPay类为一切业务类的入口
public GetBalance() {
super();
// TODO Auto-generated constructor stub
}
public GetBalance(UnionPay unionPay) {
super();
this.unionPay = unionPay;
}
public double getBalance(String cardNO) {
return ATMUtil.getCardbyCardNO(unionPay, cardNO).getAccount().getBalance();
}
}
/**
* 数据初始化类
*
* @author Administrator
* @date
*/
class InitData {
public InitData() {
// TODO Auto-generated constructor stub
}
public static UnionPay initData() {
UnionPay unionPay = new UnionPay();
Bank ccb = new Bank("1001", "中国建设银行", 0.02);
Bank icbc = new Bank("1002", "中国工商银行", 0.03);
Bank abc = new Bank("1003", "中国农业银行", 0.04);// new
unionPay.addBank(ccb);
unionPay.addBank(icbc);
unionPay.addBank(abc);// new
ATM aTM1 = new ATM("01", ccb);
ATM aTM2 = new ATM("02", ccb);
ATM aTM3 = new ATM("03", ccb);
ATM aTM4 = new ATM("04", ccb);
ATM aTM5 = new ATM("05", icbc);
ATM aTM6 = new ATM("06", icbc);
ATM aTM7 = new ATM("07", abc);// new
ATM aTM8 = new ATM("08", abc);// new
ATM aTM9 = new ATM("09", abc);// new
ATM aTM10 = new ATM("10", abc);// new
ATM aTM11 = new ATM("11", abc);// new
ccb.addATM(aTM1);
ccb.addATM(aTM2);
ccb.addATM(aTM3);
ccb.addATM(aTM4);
icbc.addATM(aTM5);
icbc.addATM(aTM6);
abc.addATM(aTM7);// new
abc.addATM(aTM8);// new
abc.addATM(aTM9);// new
abc.addATM(aTM10);// new
abc.addATM(aTM11);// new
User Yangguo = new User("360101200102122324", "杨过", "13856223254");
User Guojing = new User("360101200012302552", "郭靖", "13800021124");
User Zhangwuji = new User("360502199805163221", "张无忌", "13952110011");
User Weixiaobao = new User("360201200513243326", "韦小宝", "13025996587");
User Zhangsanfeng = new User("360102199713459810", "张三丰", "13677871290");// new
User Linghuchong = new User("360503190299878473", "令狐冲", "13609899238");// new
User Qiaofeng = new User("360607194313666711", "乔峰", "13677871290");// new
User Hongqigong = new User("363220987809872234", "洪七公", "13609009454");// new
AbstractAccount ccbAcc1 = new DebitAccount("3217000010041315709", 10000.00, Yangguo, ccb, 0, 0);
AbstractAccount ccbAcc2 = new DebitAccount("3217000010041315715", 10000.00, Yangguo, ccb, 0, 0);
AbstractAccount ccbAcc3 = new DebitAccount("3217000010051320007", 10000.00, Guojing, ccb, 0, 0);
AbstractAccount ccbAcc4 = new CreditAccount("3640000010045442002", 10000.00, Zhangsanfeng, ccb, 0.05, 50000.00);// new
AbstractAccount icbcAcc1 = new DebitAccount("3222081502001312389", 10000.00, Zhangwuji, icbc, 0, 0);
AbstractAccount icbcAcc2 = new DebitAccount("3222081502001312390", 10000.00, Zhangwuji, icbc, 0, 0);
AbstractAccount icbcAcc3 = new DebitAccount("3222081502001312399", 10000.00, Zhangwuji, icbc, 0, 0);
AbstractAccount icbcAcc4 = new DebitAccount("3222081502051320785", 10000.00, Weixiaobao, icbc, 0, 0);
AbstractAccount icbcAcc5 = new DebitAccount("3222081502051320786", 10000.00, Weixiaobao, icbc, 0, 0);
AbstractAccount icbcAcc6 =
new CreditAccount("3640000010045441009", 10000.00, Linghuchong, icbc, 0.05, 50000.00);// new
AbstractAccount abcAcc1 = new CreditAccount("3630000010033431001", 10000.00, Qiaofeng, abc, 0.05, 50000.00);// new
AbstractAccount abcAcc2 = new CreditAccount("3630000010033431008", 10000.00, Hongqigong, abc, 0.05, 50000.00);// new
ccb.addAccount(ccbAcc1);
ccb.addAccount(ccbAcc2);
ccb.addAccount(ccbAcc3);
ccb.addAccount(ccbAcc4);// new
icbc.addAccount(icbcAcc1);
icbc.addAccount(icbcAcc2);
icbc.addAccount(icbcAcc3);
icbc.addAccount(icbcAcc4);
icbc.addAccount(icbcAcc5);
icbc.addAccount(icbcAcc6);// new
abc.addAccount(abcAcc1);// new
abc.addAccount(abcAcc2);// new
Yangguo.addAccount(ccbAcc1);
Yangguo.addAccount(ccbAcc2);
Guojing.addAccount(ccbAcc3);
Zhangsanfeng.addAccount(ccbAcc4);// new
Zhangwuji.addAccount(icbcAcc1);
Zhangwuji.addAccount(icbcAcc2);
Zhangwuji.addAccount(icbcAcc3);
Weixiaobao.addAccount(icbcAcc4);
Weixiaobao.addAccount(icbcAcc5);
Linghuchong.addAccount(icbcAcc6);// new
Qiaofeng.addAccount(abcAcc1);// new
Hongqigong.addAccount(abcAcc2);// new
Card ccbCard1 = new Card("6217000010041315709", "88888888", ccbAcc1);
Card ccbCard2 = new Card("6217000010041315715", "88888888", ccbAcc1);
Card ccbCard3 = new Card("6217000010041315718", "88888888", ccbAcc2);
Card ccbCard4 = new Card("6217000010051320007", "88888888", ccbAcc3);
Card icbcCard5 = new Card("6222081502001312389", "88888888", icbcAcc1);
Card icbcCard6 = new Card("6222081502001312390", "88888888", icbcAcc2);
Card icbcCard7 = new Card("6222081502001312399", "88888888", icbcAcc3);
Card icbcCard8 = new Card("6222081502001312400", "88888888", icbcAcc3);
Card icbcCard9 = new Card("6222081502051320785", "88888888", icbcAcc4);
Card icbcCard10 = new Card("6222081502051320786", "88888888", icbcAcc5);
Card ccbCard11 = new Card("6640000010045442002", "88888888", ccbAcc4);// new
Card ccbCard12 = new Card("6640000010045442003", "88888888", ccbAcc4);// new
Card icbcCard13 = new Card("6640000010045441009", "88888888", icbcAcc6);// new
Card abcCard14 = new Card("6630000010033431001", "88888888", abcAcc1);// new
Card abcCard15 = new Card("6630000010033431008", "88888888", abcAcc2);// new
ccbAcc1.addCard(ccbCard1);
ccbAcc1.addCard(ccbCard2);
ccbAcc2.addCard(ccbCard3);
ccbAcc3.addCard(ccbCard4);
ccbAcc4.addCard(ccbCard11);// new
ccbAcc4.addCard(ccbCard12);// new
icbcAcc1.addCard(icbcCard5);
icbcAcc2.addCard(icbcCard6);
icbcAcc3.addCard(icbcCard7);
icbcAcc3.addCard(icbcCard8);
icbcAcc4.addCard(icbcCard9);
icbcAcc5.addCard(icbcCard10);
icbcAcc6.addCard(icbcCard13);// new
abcAcc1.addCard(abcCard14);// new
abcAcc2.addCard(abcCard15);// new
return unionPay;
}
}
/**
* 银联类
*
* @author Administrator
* @date
*/
class UnionPay {
private ArrayList<Bank> bankList = new ArrayList<Bank>();// 银联包含的银行列表
public UnionPay() {
super();
// TODO Auto-generated constructor stub
}
public UnionPay(ArrayList<Bank> bankList) {
super();
this.bankList = bankList;
}
public ArrayList<Bank> getBankList() {
return bankList;
}
public void setBankList(ArrayList<Bank> bankList) {
this.bankList = bankList;
}
public void addBank(Bank bank) {
this.bankList.add(bank);
}
public void removeBank(Bank bank) {
this.bankList.remove(bank);
}
}
/**
* 用户类
*
* @author Administrator
* @date
*/
class User {
private String ID;// 身份证号
private String name;// 姓名
private String Phone;// 电话号码
ArrayList<AbstractAccount> list = new ArrayList<AbstractAccount>();// 该用户拥有的账户列表(注意,账户可能隶属于不同银行
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String iD, String name, String phone) {
super();
ID = iD;
this.name = name;
Phone = phone;
}
public String getID() {
return ID;
}
public void setID(String iD) {
ID = iD;
}
public String getPhone() {
return Phone;
}
public void setPhone(String phone) {
Phone = phone;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addAccount(AbstractAccount ccbAcc1) {
this.list.add(ccbAcc1);
}
public void removeAccount(DebitAccount account) {
this.list.remove(account);
}
}
/**
* 业务类,取款类
*
* @author Administrator
* @date
*/
class Withdraw {
// 以下属性为取款需要输入的信息
private UnionPay unionPay;// 银联,一切业务操作的入口
private String cardNO;// 卡号
private String cardPassword;// 密码
private String ATMID;// ATM编号
private double amount;// 取款金额
// 根据卡号获取卡对象
private Card card = null;
// 根据ATM编号获取ATM对象
private ATM aTM = null;
// 根据卡号获取对应账号
private AbstractAccount account = null;
// 根据ATM或ATM所属银行对象
private Bank bank = null;
public Withdraw() {
super();
// TODO Auto-generated constructor stub
}
/**
*
* @param unionPay
* @param cardNO
* @param cardPassword
* @param aTMID
* @param amount
*/
public Withdraw(UnionPay unionPay, String cardNO, String cardPassword, String aTMID, double amount) {
super();
this.unionPay = unionPay;
this.cardNO = cardNO;
this.cardPassword = cardPassword;
ATMID = aTMID;
this.amount = amount;
}
/**
* 求跨行业务手续费
*
* @return
*/
public double getCrossBankCommission(double amount) {
return amount * bank.getCommission();
}
/**
* 求透支取款手续费
*
* @param amount
* @return
*/
public double getOverdrawCommission(double amount) {
return amount * account.getRatio();
}
/**
* 校验是否为跨行取款
*/
public boolean isCrossBank() {
if (account.getBank().getBankNO() != aTM.getBank().getBankNO()) {
return true;
}
return false;
}
/**
* 判断是否为信用卡
*
* @return
*/
public boolean isCreditAccount() {
if (account instanceof CreditAccount) {
return true;
}
return false;
}
/**
* 校验输入的数据是否正确 注意:该方法不支持开闭原则,大家可以思考如何设计才能针对各种银行卡均能够实现开闭原则
*
* @return
*/
public boolean checkData() {
// 获取银行卡对象
card = ATMUtil.getCardbyCardNO(unionPay, cardNO);
// 银行卡不存在(卡号错误)
if (card == null) {
System.out.println("Sorry,this card does not exist.");
return false;
}
// 获取ATM机对象
aTM = ATMUtil.getATMbyATMID(unionPay, ATMID);
// ATM机不存在(ATM ID错误)
if (aTM == null) {
System.out.println("Sorry,the ATM's id is wrong.");
return false;
}
// 获取ATM机所隶属银行对象
bank = aTM.getBank();
// 用户密码错误
if (!card.getCardPassword().equals(cardPassword)) {
System.out.println("Sorry,your password is wrong.");
return false;
}
// 根据卡号获取用户账号
account = ATMUtil.getAccountbyCardNO(cardNO);
// 如果为借记卡
if (!isCreditAccount()) {
double commission = 0;
// 如果为跨行业务,则收取跨行费用
if (this.isCrossBank()) {
commission += this.getCrossBankCommission(amount);
}
// 取款超出余额
if (amount + commission > account.getBalance()) {
System.out.println("Sorry,your account balance is insufficient.");
return false;
}
}
// 如果为信用卡
if (isCreditAccount()) {
double commission = 0; // 手续费总额
double overdrawAmount = 0; // 透支金额
double balance = 0; // 当前卡上余额
balance = account.getBalance(); // 获取当前卡余额
// 有余额,则透支金额为取款金额与余额的差值
if (balance >= 0) {
overdrawAmount = amount - account.getBalance();
} else {// 余额为负值(已经透支),则透支金额为取款金额
overdrawAmount = amount;
}
// 收取跨行业务费用
if (this.isCrossBank()) {
commission += this.getCrossBankCommission(amount);
}
// 收取透支费用
if (overdrawAmount > 0) {
commission += this.getOverdrawCommission(overdrawAmount);
}
// 如果取款金额与手续费金额之和大于卡片余额与可透支最大金额之和,无法取款
if (commission + amount > account.getBalance() + account.getOverdrawAmount()) {
System.out.println("Sorry,your account balance is insufficient.");
return false;
}
}
return true;
}
/**
* 该方法支持开闭原则
*/
public void withdraw() {
double commission = 0;
double overdrawAmount = 0;
double balance = 0;
balance = account.getBalance();
if (balance >= 0) {
overdrawAmount = amount - account.getBalance();
} else {
overdrawAmount = amount;
}
// 收取跨行费用
if (this.isCrossBank()) {
commission += this.getCrossBankCommission(amount);
}
// 收取透支费用
if (overdrawAmount > 0) {
commission += this.getOverdrawCommission(overdrawAmount);
}
if (commission + amount > balance + account.getOverdrawAmount()) {
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
this.account.setBalance(balance - amount - commission);
showResult(this.account);
}
/**
* 显示
*
* @param account
*/
public void showResult(AbstractAccount account) {
String userName = account.getUser().getName();
String bankName = aTM.getBank().getBankName();
System.out
.println("业务:取款 " + userName + "在" + bankName + "的" + ATMID + "号ATM机上取款" + String.format("¥%.2f", amount));
System.out.println("当前余额为" + String.format("¥%.2f", account.getBalance()));
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
UnionPay unionPay = InitData.initData();// 初始化程序数据
StringBuilder sb = new StringBuilder();// 用于接收输入数据
String data;
// 解析输入各行数据
while (!((data = input.nextLine()).equals("#"))) {
sb.append(data + "\n");
}
String[] dt = sb.toString().split("\n");
for (int i = 0; i < dt.length; i++) {
String[] dataLine = dt[i].toString().split("\\s+");
if (dataLine.length == 1) {// 查询余额功能
GetBalance gb = new GetBalance(unionPay);
System.out.println("业务:查询余额 " + String.format("¥%.2f", gb.getBalance(dataLine[0])));
} else {// 取款功能
Withdraw wd =
new Withdraw(unionPay, dataLine[0], dataLine[1], dataLine[2], Double.parseDouble(dataLine[3]));
if (wd.checkData()) {
wd.withdraw();
} else {
System.exit(0);
}
}
}
}
}
注意:这里的类与类之间有着很多的套娃现象,
AbstractAccount类中有User,Bank,银行卡的ArrayList<Card> list
User类中有ArrayList<AbstractAccount> list
Bank类中ArrayList<AbstractAccount> accountList,ArrayList<ATM> ATMList
各个类之间有着复杂的关联关系,因此在未理清它们各自之间的关系之前是很难做的出来的,这道题牵连的知识点也非常的多,要求对基础知识掌握牢靠。
吃透一道这样的大题需要耗费很多时间,但是对编程思路和能力的提升将有很大的帮助。



浙公网安备 33010602011771号