题目集7~9的总结

一、前言

  这一阶段的学习已经结束,题目集的题量降低,题目难度明显上升,尽管题目难度上升,但是让我们学到的东西也很多,接下来将由我分析分析。

  1.题目集07:

  

 

   本次题目集写的题目是有关图形卡片排序游戏的题目,主要要求同学们锻炼类的继承、多态性使用方法以及接口的应用。作为本阶段的初次作业,主要锻炼同学的类的继承和多态以及接口的练习,接口为后期代码的维护与拓展提供了便利并且使用接口会使代码更加严密和安全,继承和多态则提升了代码的复用性。此外还有Arraylist的用法的练习,ArrayList对于数据的处理与普通数组而言优越在其不用声明数组的大小而且使用ArrayList更符合本题要求。本次作业由于已经给了相应的类图,所以并不算很难。

 

  2.题目集08:

 

 

  本次题目集的题目做ATM机仿真作业,只有一个作业,具体考察实体类及业务类的设计与分析,当然还要求我们了解ATM机的应用背景。就我而言还是很难的,我在想不出咋做的时候就放弃了也是不对的。难度不在于题目要求实现的存款、取款以及查询余额功能,而在于类的设计,以及信息的匹配,类与类之间的调用。要求注意本题目中的各实体类之间的关系,尤其是一对多的组合关系;对实体类的设计要做到单一职责原则,且不能缺少规定的实体类;编程时考虑面向对象中的封装性本题目中的应用以及是否有能够扩展 的衍生需求。

  3.题目集09:

 

 

 

   本次作业同样是ATM机类结构设计,在题目集08之上新增了透支(信用卡)和跨行取款功能,在透支和跨行的情况下都要收取一定的手续费。在老师提供了一定代码的基础上进行设计与改进,难度在于考虑透支功能应该怎样设计,和透支以及跨行的取钱的计算方法。要求我们要进行类的继承;务必注意本题目中的各实体类之间的关系,尤其是一对多的组合关系;对实体类的设计要做到单一职责原则,且不能缺少规定的实体类;在“合成复用原则”及“单一职责原则”基础上,尽量对上次作业的程 序进行重构,使之符合 “开-闭”原则。

二、设计与分析

1.题目集7-1,7-2

7-1类图及复杂度分析图

 

 

 7-1类图分析(删除了Main类)

7-1复杂度分析

7-2类图设计及复杂度分析:

 

 

 

 

 

 

 

 

 

 

 7-2复杂度分析

 设计与分析:

  7-1:根据指导书所给的参考类图,首先编写Shape,其中包含的方法有返回图形的面积(abstract double getArea()),校验图形输入数值的合理性(abstract boolean validate()),以及属性值shapeName还有toString的方法来返回图形类;然后编写图形类(Circle、Rectangle、Triangle、Trapezoid)继承自Shape类,根据已给类图写出没给类相应属性,写出相应的求面积的方法和数据的检验方法,需要注意的是三角形的计算要用到海伦公式。接着就是Card类的编写,在其中要实现Compare接口,因为后边要用到Collections.sort();的排序方法,但是在没有更改compareTo()的方法的情况下,用Arraylist的card类型的时候会报错,因为card类型和shape连接在一起,有多种数值,所以要改写compareTo的用法如下所示:

public int compareTo(Card card) {
		//将面积进行比较
		return Double.compare(card.shape.getArea(), shape.getArea());
	}

  接着便是要写业务类DealCardList,根据已给定的Main类,来实现业务类DealCardList的功能,实现对输入数据合理性的判断,结果的输出,以及数据的存储、排序等功能(代码如下),接着便是测试所写代码。

class DealCardList{
	ArrayList<Card> cardList = new ArrayList<Card>();

	public DealCardList() {
		super();
		// TODO 自动生成的构造函数存根
	}
	public DealCardList(ArrayList<Integer> list) {
        //输入各个图形数值,并将其图形面积等数据存储到cardList中
		for(Integer a: list) {
			if(a==0) break;				
			switch(a) {
			case 1:
				double radius = Main.input.nextDouble();
				Circle circle = new Circle(radius);				
				Card card1 = new Card(circle);
				card1.getShape().setShapeName("Circle");
				cardList.add(card1);
				break;
			case 2:
				double length = Main.input.nextDouble();
				double width = Main.input.nextDouble();
				Rectangle rectangle = new Rectangle(width,length);
				Card card2 = new Card(rectangle);
				card2.getShape().setShapeName("Rectangle");
				cardList.add(card2);
				break;
			case 3:
				double side1 = Main.input.nextDouble();
				double side2 = Main.input.nextDouble();
				double side3 = Main.input.nextDouble();
				Triangle triangle = new Triangle(side1,side2,side3);
				Card card3 = new Card(triangle);
				card3.getShape().setShapeName("Triangle");
				cardList.add(card3);
				break;
			case 4:
				double topSide = Main.input.nextDouble();
				double bottomSide = Main.input.nextDouble();
				double height = Main.input.nextDouble();
				Trapezoid tropezoid = new Trapezoid(topSide,bottomSide,height);
				Card card4 = new Card(tropezoid);
				card4.getShape().setShapeName("Trapezoid");
				cardList.add(card4);
				break;
			}
		}
	}
	public boolean validate() {
        //判断输入数据合法性
		boolean boo = true;
		for(Card a:cardList) {
			if(!a.getShape().validate()) {	
				boo = false;
				break;				
			}
		}
		return boo;
	}
	public void cardSort() {
		Collections.sort(cardList);		
		for(Card card : cardList) {
			System.out.printf("%s:%.2f ",card.getShape(),card.getShape().getArea());
		}
	}
	public double getAllArea() {
        //得到所有图形总面积
		double sum = 0;
		for(Card card : cardList) {
			sum = sum+card.getShape().getArea();
		}
		return sum;
	}
	public void showResult() {
        //输出结果
		System.out.println("The original list:");
		 for (Card card : cardList) {
	            System.out.printf("%s:%.2f ",card.getShape(),card.getShape().getArea());
	        }
        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的基础上要求对面积更加细致的分组,输出要求如下图:

 

   因此要考虑怎么分组,我采用的方式是通过判断他们图形的类型通过getShapeName()与图形的匹配,将同一类型的挑选出来并根据输出要求进行调整,以便后续输出,如下:

public void show() {
		System.out.print("[");
        for(Card card1 : cardList) {       	
        	if(card1.getShape().getShapeName()=="Circle") {
        		System.out.printf("%s:%.2f ",card1.getShape(),card1.getShape().getArea());       		
        	}       	
        }
        System.out.print("]");
        System.out.print("[");
        for(Card card1 : cardList) {
        	if(card1.getShape().getShapeName()=="Rectangle") {
        		System.out.printf("%s:%.2f ",card1.getShape(),card1.getShape().getArea());       		
        	}
        }
        System.out.print("]");
        System.out.print("[");
        for(Card card1 : cardList) {
        	if(card1.getShape().getShapeName()=="Triangle") {
        		System.out.printf("%s:%.2f ",card1.getShape(),card1.getShape().getArea());       		
        	}
        }
        System.out.print("]");
    	System.out.print("[");
        for(Card card1 : cardList) {
        	if(card1.getShape().getShapeName()=="Trapezoid") {
        		System.out.printf("%s:%.2f ",card1.getShape(),card1.getShape().getArea());       		
        	}
        }
        System.out.println("]");
        
	}

  输出的方法如下:

public void showResult() {
        //输出结果
		System.out.println("The original list:");
		System.out.print("[");
		 for (Card card : cardList) {
	            System.out.printf("%s:%.2f ",card.getShape(),card.getShape().getArea());
	        }
		System.out.println("]");
		//
        System.out.println("The Separated List:"); 
        show(); 
        //
        System.out.println("The Separated sorted List:");
        cardSort();
        show();
        double[] a = new double[4]; 
        for(Card card1 : cardList) {       	
        	if(card1.getShape().getShapeName()=="Circle") {
        		a[0]+= card1.getShape().getArea();
        	}
        	if(card1.getShape().getShapeName()=="Rectangle") {
        		a[1]+= card1.getShape().getArea();
        	}
        	if(card1.getShape().getShapeName()=="Triangle") {
        		a[2]+= card1.getShape().getArea();
        	}
        	if(card1.getShape().getShapeName()=="Trapezoid") {
        		a[3]+= card1.getShape().getArea();
        	}
        }
        double temp = 0;
        for(double b:a) {
        	if(b>temp) {
        		temp = b;
        	}
        }
        System.out.printf("The max area:%.2f",temp);				
	}
}

2.题目集08,09

  题目集08:要求尝试使用面向对象技术对银行用户在 ATM 机上进行相关操作的模拟系统设计,相关概念均要设计为实体类,业务(控制)类请自行根据实际需要进 行扩充和完善。首先考虑的是都有哪些类各个类之间哪些有关系,有关系的类要怎样连接在一起;哪些类:1.实体类:在了解设计的背景后知道有哪些实体类要设计并且要知道比如账号,密码等信息究竟是属于那个类的属性,然后设计了UnionPay、Bank、ATM、User、Account、Card这些类,并且各个有关系的类之间用ArrayList连接在一起 2.业务类:拿老师的例子来说有GetBalance、ValidateData、Withdraw来实现余额的查询,存、取钱等功能。

  题目集09:在题目集08的基础上,要求增加跨行取款的功能,并且能够透支。在所提供的代码上要求实现类的继承和多态。由于增加了借贷功能,由此产生了信用卡,在实现类的继承的时候就要考虑什么类应该被继承,经过考虑应该被继承的类是Account,他的两个子类一个是CreditAccount一个是DebitAccount,然后就是信息的初始化(需要双向绑定),代码如下:

Bank ccb = new Bank("1001","中国建设银行");
    	Bank icbc = new Bank("1002","中国工商银行");
    	Bank abc = new Bank("1003","中国农业银行");
    	
    	unionPay.addBank(ccb);
    	unionPay.addBank(icbc);
    	unionPay.addBank(abc);
    	
    	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);
    	ATM aTM8 = new ATM("08",abc);
    	ATM aTM9 = new ATM("09",abc);
    	ATM aTM10 = new ATM("10",abc);
    	ATM aTM11 = new ATM("11",abc);
    	
    	ccb.addATM(aTM1);
    	ccb.addATM(aTM2);
    	ccb.addATM(aTM3);
    	ccb.addATM(aTM4);
    	icbc.addATM(aTM5);
    	icbc.addATM(aTM6);
    	abc.addATM(aTM7);
    	abc.addATM(aTM8);
    	abc.addATM(aTM9);
    	abc.addATM(aTM10);
    	abc.addATM(aTM11);
    	
    	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("360202000513243326","张三丰","13855447698");
    	User linghuchong = new User("360202200505091897","令狐冲","13933564468");
    	User qiaofeng = new User("360201202012151585","乔峰","18733587764");
    	User hongqigong = new User("360201413257815136","洪七公","13933425568");
    	
    	Account ccbAcc1 = new DebitAccount("3217000010041315709",10000.00,Yangguo,ccb);
    	Account ccbAcc2 = new DebitAccount("3217000010041315715",10000.00,Yangguo,ccb);
    	Account ccbAcc3 = new DebitAccount("3217000010051320007",10000.00,Guojing,ccb);
    	Account icbcAcc1 = new DebitAccount("3222081502001312389",10000.00,Zhangwuji,icbc);
    	Account icbcAcc2 = new DebitAccount("3222081502001312390",10000.00,Zhangwuji,icbc);
    	Account icbcAcc3 = new DebitAccount("3222081502001312399",10000.00,Zhangwuji,icbc);
    	Account icbcAcc4 = new DebitAccount("3222081502051320785",10000.00,Weixiaobao,icbc);
    	Account icbcAcc5 = new DebitAccount("3222081502051320786",10000.00,Weixiaobao,icbc);
    	Account ccbAcc4 = new CreditAccount("3640000010045442002",10000.00,zhangsanfeng,ccb);
    	Account icbcAcc6 = new CreditAccount("3640000010045441009 ",10000.00,linghuchong,icbc);
    	Account abcAcc1 = new CreditAccount("3630000010033431001",10000.00,qiaofeng,abc);
    	Account abcAcc2 = new CreditAccount("3630000010033431008",10000.00,hongqigong,abc);

    	
    	ccb.addAccount(ccbAcc1);
    	ccb.addAccount(ccbAcc2);
    	ccb.addAccount(ccbAcc3);
    	icbc.addAccount(icbcAcc1);
    	icbc.addAccount(icbcAcc2);
    	icbc.addAccount(icbcAcc3);
    	icbc.addAccount(icbcAcc4);
    	icbc.addAccount(icbcAcc5);
    	ccb.addAccount(ccbAcc4);
    	icbc.addAccount(icbcAcc6);
    	abc.addAccount(abcAcc1);
    	abc.addAccount(abcAcc2);
    	
    	Yangguo.addAccount(ccbAcc1);
    	Yangguo.addAccount(ccbAcc2);
    	Guojing.addAccount(ccbAcc3);
    	Zhangwuji.addAccount(icbcAcc1);
    	Zhangwuji.addAccount(icbcAcc2);
    	Zhangwuji.addAccount(icbcAcc3);
    	Weixiaobao.addAccount(icbcAcc4);
    	Weixiaobao.addAccount(icbcAcc5);
    	zhangsanfeng.addAccount(ccbAcc4);
    	linghuchong.addAccount(icbcAcc6);
    	qiaofeng.addAccount(abcAcc1);
    	hongqigong.addAccount(abcAcc2);

    	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);
    	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);
    	
    	
    	ccbAcc1.addCard(ccbCard1);
    	ccbAcc1.addCard(ccbCard2);
    	ccbAcc2.addCard(ccbCard3);
    	ccbAcc3.addCard(ccbCard4);
    	icbcAcc1.addCard(icbcCard5);
    	icbcAcc2.addCard(icbcCard6);
    	icbcAcc3.addCard(icbcCard7);
    	icbcAcc3.addCard(icbcCard8);
    	icbcAcc4.addCard(icbcCard9);
    	icbcAcc5.addCard(icbcCard10);
    	ccbAcc4.addCard(ccbCard11);
    	ccbAcc4.addCard(ccbCard12);
    	icbcAcc6.addCard(icbcCard13);
    	abcAcc1.addCard(abcCard14);
    	abcAcc2.addCard(abcCard15);

  我感觉有难度的是计算方法,当然这里有错,会在踩坑里边说,下面来看类图和,复杂度分析

 

 题目集09类图

 

 

三、踩坑心得

 1.题目集07

  在7-2中要求新的输出方式,因此用了大量的if语句,代码复杂度增加,此外7-2Main类较7-1不同的地方是需要先进行一次开始输入的n是否是0的判断,如果是0的话要结束进程,并输出Wrong Format,我采用的方法是判断list的数组大小是否为0,如果是0,就结束进程并输出Wrong Format。因此做了如下改进:

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);
		}
		dealCardList.showResult();
		

  7-1中的代码

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();
		}
		if(list.size()==0) {
			System.out.println("Wrong Format");
			System.exit(0);
		}
		DealCardList dealCardList = new DealCardList(list);
		if(!dealCardList.validate()){
		System.out.println("Wrong Format");
		System.exit(0);
		}
		dealCardList.showResult();

  7-2中的代码

2.题目集08、09

  在题目集09中我的计算取款方法如下:先判断是否跨行,并且如果跨行就先将手续费算出来,然后再判断余额,在判断账户是否为借贷账户,如果是并且在余额小于0的情况下,小于0的部分收取手续费,然后再判断余额,但是这样就出现了一个问题,就是如果借贷的情况下,第一次取款借贷了,并且此时余额已经小于0,那当我第二次取款,如果按照我写的代码,就会将第二次取的钱和第一次小于0的钱再算一遍手续费,也就是手续费收多了。所以此法不同,另行他法

/**
		 * 校验是否为跨行取款
		 * 1001:2% 1002:3% 1003:4%
		 * 透支收费为已透支费用的5%
		 */
		if (account.getBank().getBankNO() != aTM.getBank().getBankNO()) {
			if(aTM.getBank().getBankName() == "中国建设银行") {
				rebalance = balance - amount - 0.02*amount;
			}
			if(aTM.getBank().getBankName() == "中国工商银行") {
				rebalance = balance - amount - 0.03*amount;
			}
			if(aTM.getBank().getBankName() == "中国农业银行") {
				rebalance = balance - amount - 0.04*amount;
			}
		}	
		
		if(account.getBank().getBankNO() == aTM.getBank().getBankNO()){
			rebalance = balance - amount;//取款更新余额操作	
		}
		
		
		
		if(account.toString().equals("DebitAccount")) {
			if(rebalance < 0) {
				System.out.println("Sorry,your account balance is insufficient.");
                System.exit(0);
			}
			else if(rebalance >= 0){
				account.setBalance(rebalance);
			}
		}
		double balance1 = 0;
		if(account.toString() .equals("CreditAccount")) {
			if(rebalance >= 0) {
				account.setBalance(rebalance);
			}
			else if(rebalance < 0) {
				balance1 = rebalance + 0.05*rebalance;
				if(rebalance < -50000) {
					System.out.println("Sorry,your account balance is insufficient.");
                    System.exit(0);
				}
				else{
					account.setBalance(balance1);
				}
			}

四、改进建议

  再进行一些重复性较多的代码编写的时候,应该充分提高代码的复用性,并且尽可能提升代码的安全性,并做好封装,此外如果业务类要实现的功能很多,应该尽可能细化,实现单一性原则。

五、总结

  通过本阶段的学习,总体来说锻炼的就是开闭原则和单一性原则的锻炼,而且我深刻认识到设计一个程序的难度,有时候根本就是无从下手,并且在设计的时候还要考虑多种类的特性,然后就是作业虽然有难度但是学到的东西也很多,比如接口啥的。

  

posted @ 2021-06-20 00:03  悟陉  阅读(88)  评论(0)    收藏  举报