第三次作业Blog总结
一、作业总结
这三次作业相对于之前两次作业,作业量并没有增加,但是难度系数相较之有所增加了。之前所考察的多态、继承、封装、接口等,本次作业均有所考察,并且大多放在同一次题目集进行考察,所以复杂度大大提高了,所需要耗时更多了。
但是对于题目集8,我写的代码类间设计存在一定的问题,并且,没有很好的理解ArrayList的用法,代码缺少扩展性和维护性。所以,该次作业虽然PTA的测试点都通过了,但是单独将代码拿出来还是很有问题的。
下面我就对这三次题目集做个简要分析。
- 图形卡片排序游戏(题目集7)
作业指导中有给出完整的类图和主方法源码,这对我们做题有很大的指导。对于这道题,考察的就是类的继承、多态性使用方法以及接口的应用。题中要求设计圆形(Circle)、矩形(Rectangle)、三角形(Triangle)及梯形(Trapezoid)四种卡片类型,四种卡片均继承于Shape类。另有要求对卡片排序时使用Comparable接口,即Card类需要实现Comparable接口中的CompareTo()方法。这是学习java以来第一次使用Comparable接口,所以开始学习的时候费了点时间,学习了以后发现使用起来非常方便。
SourceMonitor生成报表内容如下:

圈复杂度只有7,题目比较简单,所以代码也比较简单,复杂程度并不高,稍微在接口处学习下就能做好题。
PowerDesigner类图如下:

只有几处使用了数组遍历,提高了代码的复杂程度,例如:
public boolean validate(){
for(Card card : cardList)
{
if(card.getShape().validate())
return true;
else
return false;
}
return true;
}
此题还有的重点在于排序,排序代码如下:
public void cardSort(){
for(int i = 0; i < cardList.size(); i++)
{
for(int j = i + 1; j < cardList.size(); j++)
{
if(cardList.get(i).getShape().getArea() < cardList.get(j).getShape().getArea())
Collections.swap(cardList,i,j);
}
}
}
public double getAllArea(){
double sumarea = 0;
for(Card card : cardList)
{
sumarea += card.getShape().getArea();
}
return sumarea;
}
输出方法:
public void showResult(){
System.out.println("The original list:");
for(int i = 0; i < cardList.size(); i++)
{
System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" ");
}
System.out.println();
System.out.println("The sorted list:");
cardSort();
for(int i = 0; i < cardList.size(); i++)
{
System.out.print(cardList.get(i).getShape().getShapeName()+":"+String.format("%.2f",cardList.get(i).getShape().getArea())+" ");
}
;
System.out.println();
System.out.println("Sum of area:"+String.format("%.2f",getAllArea()));
}
2.图形卡片分组游戏(题目集7)
这道题与第一题类似,只是在7-1的基础上进一步改进和完善。
由如下SourceMonitor生成报表可以看到,圈复杂程度并没有较大提高,因为较之7-1,只是输出方式和排序方式有所改变,其他的并没有大的变化。

7-1是从小到大排序,而7-2是在每一个图形集合里进行排序。
排序算法如下:
public void cardSort(){
Collections.sort(circles);
Collections.sort(rectangles);
Collections.sort(triangles);
Collections.sort(trapezoids);
String s1="",s2="",s3="",s4="";
System.out.print("[");
for(int i=circles.size()-1;i>=0;i--)
s1=s1+circles.get(i).toString()+" ";
System.out.print(s1);
System.out.print("]");
System.out.print("[");
for(int i=rectangles.size()-1;i>=0;i--)
s2=s2+rectangles.get(i).toString()+" ";
System.out.print(s2);
System.out.print("]");
System.out.print("[");
for(int i=triangles.size()-1;i>=0;i--)
s3=s3+triangles.get(i).toString()+" ";
System.out.print(s3);
System.out.print("]");
System.out.print("[");
for(int i=trapezoids.size()-1;i>=0;i--)
s4=s4+trapezoids.get(i).toString()+" ";
System.out.print(s4);
System.out.print("]");
}
输出代码如下:
public void showResult(){
System.out.println("The original list:");
System.out.print("[");
double[] s=new double[4];
for (Card card:cardArrayList){
System.out.print(card.getShape()+" ");
}
System.out.print("]");
System.out.println();
System.out.println("The Separated List:");
System.out.print("[");
for(Circle circle:circles)
{ System.out.printf("Circle:%.2f ",circle.getArea());
s[0]=s[0]+circle.getArea();}
System.out.print("]");
System.out.print("[");
for(Rectangle rectangle:rectangles)
{ System.out.printf("Rectangle:%.2f ",rectangle.getArea());
s[1]=s[1]+rectangle.getArea();}
System.out.print("]");
System.out.print("[");
for(Triangle triangle:triangles)
{System.out.printf("Triangle:%.2f ",triangle.getArea());
s[2]=s[2]+triangle.getArea();}
System.out.print("]");
System.out.print("[");
for(Trapezoid trapezoid:trapezoids)
{ System.out.printf("Trapezoid:%.2f ",trapezoid.getArea());
s[3]=s[3]+trapezoid.getArea();}
System.out.print("]");
System.out.println();
System.out.println("The Separated sorted List:");
cardSort();
System.out.println();
double max=s[0];
for(int i=0;i<4;i++){
if(s[i]>=max)
max=s[i];
}
System.out.printf("The max area:%.2f",max);
}
对比PowerDesigner生成的7-2类图和7-1类图并无太大的差别。

3.ATM机类结构设计(一)(题目集8)
说实话,刚做这道题的时候,根本没有思路,完全写不出来,题目有些晦涩难懂,可能是因为太多的类设计非常复杂,一环套一环,思路很乱,不知从何下手。题目给的信息还算比较全面的,但其实有一些在最后运行中可能用不上,但如果在实际生活中,是有必要的。例如账户,其实在输入输出中未曾出现过,但其实在类间套中还是发挥了很大的作用,在最初的代码中,由于发现很多类其实用不太到,所以没有在代码中并没有加入相应类。类间关系设计又问题,另外,ArrayList用得不对,未能很好的弄清楚ArrayList是做什么的,导致代码没有扩展性和维护性。主类写的过于复杂,非常不整洁。主类内用的都是for循环内的if-else语句,所以说代码没有扩展性和维护性,没有实现面向对象的思维。
主类如下:
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String sa="";
double m0=10000;
double m1=10000;double m2=10000;double m3=10000;
sa=in.nextLine();
String a[]=sa.split("\\s+");
while(!sa.equals("#")){
//System.out.println(a[0]);
China china=new China();
User user=new User();
Bank bank=new Bank();
bank.useradd();
bank.useratm();
user.addcard();
int t=0;
if(a.length==1)
{
for(int i=0;i<user.card0.size();i++)
{
if(a[0].equals(user.card0.get(i).card))
{t=1;
System.out.println("¥"+String.format("%.2f",m0));
//System.exit(0);
}
}
for(int i=0;i<user.card1.size();i++)
{
if(a[0].equals(user.card1.get(i).card))
{t=1;
System.out.println("¥"+String.format("%.2f",m1));
}
}
for(int i=0;i<user.card2.size();i++)
{
if(a[0].equals(user.card2.get(i).card))
{t=1;
System.out.println("¥"+String.format("%.2f",m2));
}
}
for(int i=0;i<user.card3.size();i++)
{
if(a[0].equals(user.card3.get(i).card))
{t=1;
System.out.println("¥"+String.format("%.2f",m3));
}
}
if(t==0) {
System.out.println("Sorry,this card does not exist.");
System.exit(0);
}
}
t=0;
int s=0;
if(a.length==4)
{for(int i=0;i<user.card0.size();i++)
{
if(!a[0].equals(user.card0.get(i).card))
{
s++;
}
}
for(int i=0;i<user.card1.size();i++)
{
if(!a[0].equals(user.card1.get(i).card))
{
s++;
}
}
for(int i=0;i<user.card2.size();i++)
{
if(!a[0].equals(user.card2.get(i).card))
{
s++;
}
}
for(int i=0;i<user.card3.size();i++)
{
if(!a[0].equals(user.card3.get(i).card))
{
s++;
}
}
if(s==10)
{
System.out.println("Sorry,this card does not exist.");
System.exit(0);
}
if(a[1].equals("88888888")) {
if(a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name)||a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name))
{
for(int i=0;i<user.card0.size();i++)
{t=1;
if(a[0].equals(user.card0.get(i).card)&&a[1].equals(user.card0.get(i).password)&&(a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name)||a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name)))
{
if(a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name))
{
System.out.println("Sorry,cross-bank withdrawal is not supported.");
System.exit(0);
}
if(m0<Double.parseDouble(a[3]))
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
if(Double.parseDouble(a[3])>0)
{
System.out.println("杨过在中国建设银行的"+a[2]+"号ATM机上取款¥"+String.format("%.2f",Double.parseDouble(a[3])));
m0=m0-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m0));
}
if(Double.parseDouble(a[3])<0)
{
System.out.println("杨过在中国建设银行的"+a[2]+"号ATM机上存款¥"+String.format("%.2f",-Double.parseDouble(a[3])));
m0=m0-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m0));
}
}
}
for(int i=0;i<user.card1.size();i++)
{
if(a[0].equals(user.card1.get(i).card)&&a[1].equals(user.card1.get(i).password)&&(a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name)||a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name)))
{if(a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name))
{
System.out.println("Sorry,cross-bank withdrawal is not supported.");
System.exit(0);
}
if(m1<Double.parseDouble(a[3]))
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
if(Double.parseDouble(a[3])>0)
{
System.out.println("郭靖在中国建设银行的"+a[2]+"号ATM机上取款¥"+String.format("%.2f",Double.parseDouble(a[3])));
m1=m1-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m1));
}
if(Double.parseDouble(a[3])<0)
{
System.out.println("郭靖在中国建设银行的"+a[2]+"号ATM机上存款¥"+String.format("%.2f",-Double.parseDouble(a[3])));
m1=m1-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m1));
}
}
}
for(int i=0;i<user.card2.size();i++)
{
if(a[0].equals(user.card2.get(i).card)&&a[1].equals(user.card2.get(i).password)&&(a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name)||a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name)))
{if(a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name))
{
System.out.println("Sorry,cross-bank withdrawal is not supported.");
System.exit(0);
}
if(m2<Double.parseDouble(a[3]))
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
if(Double.parseDouble(a[3])>0)
{
System.out.println("张无忌在中国工商银行的"+a[2]+"号ATM机上取款¥"+String.format("%.2f",Double.parseDouble(a[3])));
m2=m2-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m2));
}
if(Double.parseDouble(a[3])<0)
{
System.out.println("张无忌在中国工商银行的"+a[2]+"号ATM机上存款¥"+String.format("%.2f",-Double.parseDouble(a[3])));
m2=m2-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m2));
}
}
}
for(int i=0;i<user.card3.size();i++)
{
if(a[0].equals(user.card3.get(i).card)&&a[1].equals(user.card3.get(i).password)&&(a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name)||a[2].equals(bank.atm1.get(0).name)||a[2].equals(bank.atm1.get(1).name)))
{if(a[2].equals(bank.atm.get(0).name)||a[2].equals(bank.atm.get(1).name)||a[2].equals(bank.atm.get(2).name)||a[2].equals(bank.atm.get(3).name))
{
System.out.println("Sorry,cross-bank withdrawal is not supported.");
System.exit(0);
}
if(m2<Double.parseDouble(a[3]))
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
if(Double.parseDouble(a[3])>0)
{
System.out.println("韦小宝在中国工商银行的"+a[2]+"号ATM机上取款¥"+String.format("%.2f",Double.parseDouble(a[3])));
m3=m3-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m3));
}
if(Double.parseDouble(a[3])<0)
{
System.out.println("韦小宝在中国工商银行的"+a[2]+"号ATM机上存款¥"+String.format("%.2f",-Double.parseDouble(a[3])));
m2=m2-Double.parseDouble(a[3]);
System.out.println("当前余额为¥"+String.format("%.2f",m3));
}
}
}
}
else{
System.out.print("Sorry,the ATM's id is wrong.");
System.exit(0);
}
}
else {
System.out.print("Sorry,your password is wrong.");
System.exit(0);
}
}
sa=in.nextLine();
a=sa.split("\\s+");
}
}
}
可以看到代码写的很没有条理。
由SourceMonitor的生成报表和PowerDesigner生成的类图如下:


所以在下一次作业时,老师给了源码,在源码基础上进行改编,难度降低了很多。
4.ATM机类结构设计(二)
9-1是在8-1的基础上进行跨行取款操作,由于老师给了源码,增加的难点只是现在银行卡分为借记卡和信用卡,实现跨行取款的基础上,需要考虑手续费的大小,是否透支取款,并且是否超过透支的最大额度等等。考察的点比较多,需要考虑的细节也就比较多。这道题实际上难度已经极大减少,我在写代码的过程中也没有太多的疑问,唯一困住的就是在写手续费相关算法时不太会算,这可能和本身数学不太好有关吧。因为这本身毕竟只是一个很简单的数学问题。所以在写整道题上并没有花太多时间,一个多小时就写完了。
在实现取款余额更新的地方,需要判断是借记卡还是信用卡,我使用了正则表达式来判断:
//取款更新余额操作
Pattern pattern01 = Pattern.compile("62\\d{17}");
Matcher matcher01 = pattern01.matcher(cardNO);
if(matcher01.find())
{
if(account.getBank().getBankNO() != aTM.getBank().getBankNO()) {
account.setBalance(balance - amount - amount * aTM.getCharges());
}
else
account.setBalance(balance - amount);
if(account.getBalance() < 0)
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
if (balance - amount < 0) {
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
}
Pattern pattern02 = Pattern.compile("66\\d{17}");
Matcher matcher02 = pattern02.matcher(cardNO);
if(matcher02.find())
{
if(amount > balance)
{
if(balance > 0)
{
if(account.getBank().getBankNO() != aTM.getBank().getBankNO()) {
account.setBalance(balance - amount - amount * aTM.getCharges() - (amount - balance) * 0.05);
}
else
account.setBalance(balance - amount - (amount - balance) * 0.05);
if((balance - amount) < -50000.00)
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
}
else if(balance - amount > -50000.00 && balance <= 0)
{
if(account.getBank().getBankNO() != aTM.getBank().getBankNO())
account.setBalance(balance - amount - amount * aTM.getCharges() - amount * 0.05);
else
account.setBalance(balance - amount - amount * 0.05);
}
else
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
}
else
{
if(account.getBank().getBankNO() != aTM.getBank().getBankNO()) {
account.setBalance(balance - amount - amount * aTM.getCharges());
}
else
account.setBalance(balance - amount);
}
if(account.getBalance() < -50000)
{
System.out.println("Sorry,your account balance is insufficient.");
System.exit(0);
}
}
PowerDesigner类图和SourceMonitor生成报表内容如下:


圈复杂度还有23说明还是写的有些复杂了。
二、踩坑心得
对于题目集7踩坑倒不是很大,做题目的过程并没有遇到特别难的点,问题最多的就当属题目集8的8-1了。这道题的类设计我做的很有问题。例如同样的Account类:
老师写的部分代码:
class Account{
private String accountNO;
private double balance = 0;
private User user = null;
private Bank bank = null;
private static ArrayList<Card> list = new ArrayList<Card>();
public Account() {
super();
// TODO Auto-generated constructor stub
}
public Account(String accountNO, double balance, User user, Bank bank) {
super();
this.accountNO = accountNO;
this.balance = balance;
this.user = user;
this.bank = bank;
}
public void addCard(Card card) {
list.add(card);
}
public void removeCard(Card card) {
list.remove(card);
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public String getAccountNO() {
return accountNO;
}
public void setAccountNO(String accountNO) {
this.accountNO = accountNO;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Bank getBank() {
return bank;
}
public void setBank(Bank bank) {
this.bank = bank;
}
public ArrayList<Card> getList() {
return list;
}
public void setList(ArrayList<Card> list) {
Account.list = list;
}
public static Account getAmountbyCardNO(String cardNO) {
Iterator<Card> cardItr = Account.list.iterator();
Card card = null;
while(cardItr.hasNext()) {
card = cardItr.next();
if(card.getCardNO().equals(cardNO)) {
return card.getAccount();
}
}
return null;
}
}
我写的部分代码:
class Account{
ArrayList<BankCount> mycount=new ArrayList<>();
public void Yangguo(){
BankCount one=new BankCount("中国建设银行","3217000010041315709");
BankCount two=new BankCount("中国建设银行", "3217000010041315715");
one.cardnumb.add("6217000010041315709");
one.cardnumb.add("6217000010041315715");
two.cardnumb.add("6217000010041315718");
mycount.add(one);
mycount.add(two);
}
public void Guojing(){
BankCount one =new BankCount("中国建设银行","3217000010051320007");
one.cardnumb.add("6217000010051320007");
}
public void Zhangwuji(){
BankCount one=new BankCount("中国工商银行", "3222081502001312389");
BankCount two=new BankCount("中国工商银行","3222081502001312390");
BankCount three=new BankCount("中国工商银行", "3222081502001312399");
one.cardnumb.add("6222081502001312389");
two.cardnumb.add("6222081502001312390");
three.cardnumb.add("6222081502001312399");
three.cardnumb.add("6222081502001312400");
mycount.add(one);
mycount.add(two);
mycount.add(three);
}
public void Weixxiaobao(){
BankCount one =new BankCount("中国工商银行", "3222081502051320785");
one.cardnumb.add("6222081502051320785");
BankCount two=new BankCount("中国工商银行", "3222081502051320786");
two.cardnumb.add("6222081502051320786");
mycount.add(one);
mycount.add(two);
}
}
可以很明显的对比出我的类写的并不好,类间设计存在很大的问题。看了老师的主类后,我才知道原来这些个人信息都是要放在主类内。我现在写的代码只需要有几个人的信息,那如果成百上千人的信息的时候,我的代码就完全失效了。所以,从长远考虑,如若未来做大工程的项目,需要庞大的用户信息,类设计是非常重要的,类设计没有写好,后续的问题会非常大。
三、改进建议
这三次题目集的SourceMonitor生成报表可以看到,我的代码圈复杂程度都比较高,有一次题目甚至达到了78,这是个非常需要改进的问题。
另外,老师有强调过一些地方要学会写注释,由于很多时候写代码的时候我自己的已经能看懂才会写上去,所以注释经常会忘记或认为这个地方好像不太需要写相应注释,这个问题需要改进。
最后,每次写题我都有点拖延,这是个大问题,需要改进。
四、总结
从题目集1到现在的题目集9,难度真的跨越度还蛮大的,但是一次次的题目集的练习,写代码的技巧,算法能力,速度都有所提升了。但是说是否每一次题目我都很好的理解透彻彻了,这肯定是没有的,我还有很多不懂的地方,比如说正则表达式还是用的一般般,只能一些简单的用法,每次使用还要借助网页的正则表达式测试工具;再者,类设计这个大问题希望在日后的学习中能相应改进,能设计得规范、逻辑性强。
最后,希望老师能日后继续多多指正我的问题,希望我在Java的程序学习上少走弯路!