前言:
由于即将来到学习的尾声部分了,学习的知识总是更加的深入了,所掌握的知识与所肩负的责任是相匹配的,那么我们所要解决的问题也会越来越难,这也是理所应当的,因为人不会总是停留在同一个level上,会进步,就像要解决的题目一般,所以这次的题目集的难度是在可接受范围内的~~~~
(1)nchu-software-oop-7 是三个题目集中的第一个题目, 总的要求大概就是对于类的设计是否达到完美的状态,如类的设计比较全面的话,那么就不需要担心什么,所有的问题都会迎刃而解。
难度:中等
题量:2题
知识点:类的设计、HashMap的使用、以及一些集合。
(2)nchu-software-oop-8 这个题目集遇上一个题目集有所不同的是涉及到了有关于现实生活中类的设计,Bank银行是我们在生活中经常会用到的实体生活场景,所以对于这种的类的设计所要考虑的东西只会更多,比如Bank类与Account类、Person类、Card类的关系(是依赖、聚合、关联)还是什么关系、同学必须对他们的类的关系了如指掌。否则将无法完成这次题目集、
难度:较难
题量:1题
知识点:类的关系、多重类的调用、 ArrayList数组的使用
(3)nchu-software-oop-9 它是在题目集8的基础上进行的加强版,同样是实现银行ATM系统。一般情况下,能做出题目集8并且完善后,那么题目集9的功能的增加也能很好的完成。
难度:高等
题量:1题
知识点:类的使用、类的关系的明确、方法的调用
就上述的三个题目集来概括,题目的难度逐步提高。甚至到了后面的题目集需要与同学经过一番讨论才能或许可以讨论出正确的类的设计,因为如果类的关系想错了的话,可能会产生一步错步步错的结果,为后面的题目集的改进增加了难度。
设计与分析:本次将重点分析题目集7(7-1)、(7-2)两道题目的递进式设计与题目集8和题目集9的两道ATM机仿真题目的设计分析
(1)题目集7的7-1
—————————————————————题目————————————————————————————————
解题分析:由题目要求我们可以知道,根据用户输入数据,然后我们对于输入的数据进行一个处理,在进行输出即可。 在处理的过程中,我们只需要设计一个处理的函数即可,然后对相关数据进行输出。
首先:给出相关的类图以供参考
那么我们就来看看对于输入的处理是怎么样的趴~
首先是一段代码的灵魂Main函数:
public class Main {
public static Scanner input = new Scanner(System.in);
public static void main(String[] args){
ArrayList list = new ArrayList();
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();
input.close();
}
}
在Main中可以看到我们首先定义了一个List的数组用于储存数据,然后同时定义了一个DealCard List的类用于处理数据,同时在这个类中也有对于数据的处理。
那么一个大体的Mian函数就是这样,接下来我们要做的就是对于类的实现与方法的书写了,从相关的类图我们可以看到一共是设计了7个类。分别是Card类、Shape类、Circle类、Rectangle类、Triangle类、Traperiod类、Deal Card List类。
这些类中的图形类都继承与Shape类,然后再各自的类中有对于它们从Shape类中继承来的方法的根据自己图形的重写。如每个图形的求面积的方法是不同的,那么就对于方法的getArea()的重写。
这边再给出Shape类以供参考:
class Shape {
private String shapeName;
Shape(){
}
Shape(String shapeName){
this.shapeName=shapeName;
}
public String getShapeName() {
return shapeName;
}
public void setShapeName(String shapeName) {
this.shapeName=shapeName;
}
public double getArea() {
return 0.0;
}
public boolean vaildate() {
return true;
}}
然后重点就在于对于DealCardList类的书写了
其实摸清套路后,这个类的书写确实也不算难,在这个类中,我总共设计了四个方法。
第一个方法:对于输入数据的处理,因为对于输入进的数据是保存在一个List的数组中的,我们只需要根据输入的信息对相应的图形进行匹配即可,然后把匹配好的图形数据储存在Shape类的数组中。
第二个方法:validate()的方法,用于检验数据的合法性,若数据不和法,则立即停止输出,运行终止即可。
第三个方法:card Sort的方法:用于对数据的计算,按题目要求我们需要算出所有图型的面积的和,然后给它们按照从大到小的顺序排序输出。那么在这个方法中,我们便要实现这种功能。
第四个方法:showResult()的方法,就是一个简单的按照格式输出的方法,按要求输出即可。
如果按照上述思路做题的话,要过测试点的话也不算太难,认真即可。
——————————————————————————————————————————————————————————————————
(2)题目集7的7-2
解题分析:在做过7-1的基础上,我们对于大体的解题思路都有了很清晰的了解,在7-2中,同样也没有发生改变,所改变的大概就是输出的格式罢了,用中括号括起来的话,可能就是我们需要进行一个类的数组,比如Circle的类ArrayList 、然后其他的图形的数组,然后对数组统一的进行输出即可。其他的无需大的改动。
需要注意的是在本题中我们只需要执行开闭原则即可,如在7-1的对比中,我们新加了一种图形,然后还新加了一个对于面积的算法,那么我们对于源先的代码没有改动的必要,我们只需在原来的基础上进行代码的增加以及调用即可。
通过这一题我们进一步深入理解面向对象设计原则中的“单一职责”原则和“开-闭”原则。
这里给出相应的相应的类图以供参考:
sourcemonitor图
可以看出该题目的难度其实并不大,按照我们的实际学习情况,还是能解决的!
———————————————————————————————————————————————————————————————————————
(3)题目集8的7-1
请看题:
首先,当我拿到这道题的时候我是一脸懵逼的,这是个什么题!!!
为什么分开来我看的懂,当它合并在一起时我却看不懂了,银行、ATM机、Account类???这些是什么东西!虽然在日常生活中,我们每天都要接触到这种系统,可是真的让我们放手去写的时候,才真正的感受到它的难度了,Bank与Person类到底是什么关系,而Account与Bank还有Card又是什么关系呢?!非常值得思考的问题,这不仅仅能让我们锻炼到我们的编程能力,而且还可以把问题与实际生活连接起来。
在这个问题中,最重要的是思考清楚各个类之间俺的关系,只要思考清楚关系了,然后思路清晰的话,那么后面的问题也就迎刃而解了。
那么,我们先系统的了解一下类之间的关系吧!
在这道题中,我们主要使用到的关系有三种,关联、聚合、组合、依赖
下面给出图示以供学习
解题思路:我们根据自己在脑海中构建出的大体框架。了解它们的类的关系。
那么接下来代码的实现就很简单了。
在这次的实验中,主要用的的工具有:ArrayList数组、TreeSet的方法。总体来说,代码的实现不难,就是我们要知道,想要做好一个系统,是一步步实现的,不可能一步登天。那么我们就要根据Java的语言规范,一步步的完善我们的代码。直到它能实现所有的功能。
解题步骤:
1、首先,我们要总体的把所有的数据录入到我们的库中,即把所有的用户数据录进我们的系统。
其实录入数据的方法很简单,即把所有的数据都保存在一个数据类的数组中,为了操作简便,我们设计了一个Deal类用来更好的处理数据。来让我们看看这个类的书写吧。
Deal(){
Scanner sc = new Scanner(System.in);
String password="88888888";
double money=10000;
int sware=1;
Bank bank1= new Bank("中国建设银行");
Bank bank2=new Bank("中国工商银行");
ATM atm1=new ATM("01");
ATM atm2=new ATM("02");
ATM atm3=new ATM("03");
ATM atm4=new ATM("04");
ATM atm5=new ATM("05");
ATM atm6=new ATM("06");
bank1.atmsAdd(atm1);
bank1.atmsAdd(atm2);
bank1.atmsAdd(atm3);
bank1.atmsAdd(atm4);
bank2.atmsAdd(atm5);
bank2.atmsAdd(atm6);
User use1=new User(1,"杨过");
Account account1 = new Account("3217000010041315709",money);
Card card1 = new Card ("6217000010041315709",password);
Card card2 = new Card ("6217000010041315715",password);
account1.add(card1);
account1.add(card2);
Account account2 = new Account("3217000010041315715",money);
Card card3 = new Card ("6217000010041315718",password);
account2.add(card3);
use1.add(account1);
use1.add(account2);
list.add(use1);
User use2=new User(1,"郭靖");
Account account3 = new Account("3217000010051320007",money);
Card card4 = new Card ("6217000010051320007",password);
account3.add(card4);
use2.add(account3);
list.add(use2);
User use3=new User(2,"张无忌");
Account account4 = new Account("3222081502001312389",money);
Card card5 = new Card ("6222081502001312389",password);
account4.add(card5);
Account account5 = new Account("3222081502001312390",money);
Card card6 = new Card ("6222081502001312390",password);
account5.add(card6);
Account account6 = new Account("3222081502001312399",money);
Card card7 = new Card ("6222081502001312399",password);
Card card8 = new Card ("6222081502001312400",password);
account6.add(card7);
account6.add(card8);
use3.add(account4);
use3.add(account5);
use3.add(account6);
list.add(use3);
User use4=new User(2,"韦小宝");
Account account7 = new Account("3222081502051320785",money);
Card card9 = new Card ("6222081502051320785",password);
account7.add(card9);
Account account8 = new Account("3222081502051320786",money);
Card card10 = new Card ("6222081502051320786",password);
account8.add(card10);
use4.add(account7);
use4.add(account8);
list.add(use4);
}
首先,在Deal的构造函数中,把所有的数据初始化。然后,后面对于数据的处理就很方便了。
2、根据题目要求,当用户输入错误数据时,如输入的ATM机错误,或输入的账号错误等,或取款金额大于账户余额,都直接根据错误的模式输出错误。然后停止运行即可。
那么这个功能即数据检测功能,只需要在Deal类的search中处理即可。只要匹配的信息错误,那么下一步检测错误的具体方向,然后根据错误的点直接输出即可。
public void search() {
int m=list.size(),n=inlist.size();
int s=0, j, k,set=0;
for(int i=0;i<n;i++) {
s=0;
if(inlist.get(i).card.equals("#"))
break;
for(j=0;j<m;j++) {
if(list.get(j).search(inlist.get(i).card)==true){
set=1;
s=1;
break;
}
}
if(s==0) {
System.out.println("Sorry,this card does not exist.");
//break;
}
else {
if(inlist.get(i).password.equals("#")) {
list.get(j).output(inlist.get(i).card);
//break;
}
else if(research(inlist.get(i).password)) {
int x;
if(inlist.get(i).ATM<1||inlist.get(i).ATM>6)
System.out.println("Sorry,the ATM's id is wrong.");
else{
if(inlist.get(i).ATM>0&&inlist.get(i).ATM<5)
x=1;
else
x=2;
if(x==list.get(j).bank) {
list.get(j).flow(inlist.get(i).card,inlist.get(i).money,inlist.get(i).ATM);
//break;
}
else {
System.out.println("Sorry,cross-bank withdrawal is not supported.");
//break;
}
}
}
else {
System.out.println("Sorry,your password is wrong.");
//break;
}
}
}
}
关于这些Card类、Person类、Bank类、Date类、User类、Account类、ATM类、Deal类的设计,大家只需要多关注关注多思考实际生活中它们的实际操作关系即可。
代码的实现起来,也还算简单,并不太难。接下来让我们一起来看看测试点吧。
在10 个测试点中,较难能通过的测试点,基本上没有,若算法强打的话,基本上能一次性通过,最后要注意的是输出的格式问题。存取款文图,以及需要打印的一些例如人名币的符号等等。
之后就没什么问题了,因为在本题中涉及到的基本都是较为简单的无银行之间的交往问题。
要想通过本题,细心即可。
以及对应的SourceMonitor的难度分析图
由该图可看出其难度在品均值水平,并不算难。我们所要做的就是细心考虑每个可能错误的地方,然后把它修改过来
————————————————————————————————————————————————————————————————————————
(5)题目集9的7-1
这一次的题目集是根据题目集8改进过来的题目,相较于题目集8更加的贴近于生活,如在题目集8中,我们用户不能实现跨行取款,并且没有现实生活中的借记卡的类型,无法向银行借款,或者在银行取款没有手续费这一说法等等……这都与实际生活不符合。无法与实际连接起来。所以我们对这一次的题目的改进,虽然增加了难度,但相应的也更加贴切生活。
如下给出题目:
解题分析:
实际上,题目的大体与题目集8的大体相似,但是并不能是完全的硬搬上去就行的。在这次中,较为难的两大难点是对于跨行取款和借记卡的处理,以及由于各个银行之间的利息不同,要处理的数据量较比于之前的比较庞大,很难处理好,但是尽管如此我们还是要有耐心才好,
根据红色字体可知,不仅仅我们增加了新的用户,还增加了银行和卡的类型,新增的借记卡为我们的题目带来了很大的难度,各个银行之间利率的转换。
在本次题目中总共用到了进700行的代码,足以体现它的难度了。
虽然但是,生活还得继续,该截至的还是会如期而至。我们只能继续战斗!!!拼搏向前!!
那么就来简单说说对于不同银行利率的处理吧~
相较于题目集8 我们只需要在Bank的属性中,新增加一个属性。即interst属性(利率)然后在数据初始化时记得把每个银行的利率属性赋值即可,在下次要用到这个属性的时候,直接对这个属性进行调用,便可以得到我们想要的属性了!
这边给出Bank的属性以供参考。
踩坑心得:
(1)首先,我们一般在编译器中写代码,不一定会把所有的Java类的名称命名为Main类,所以在我们把代码复制到pta上时,时常会忘记修改类名,导致编译错误,所以下次千万要记得把类名修改过来。
如在这里我就忘记把类名修改为Main,所以出现了编译错误,这个要时时刻刻记在心里,因为一次惨痛的经历,下次在也不敢忘记了。
2.比如在题目集8中的ATM机的存取款手续中,里面涉及到大量的关于存取款的操作,我们如果,有哪一个测试点无法通过的话,那么我们只需要输入它给我们的测试时间,看看它会输出什么,然后我们在进行相应的修改,即可。
这样,我们就有修改的思绪,不会像一个无头苍蝇乱撞。
像这里的部分正确,大多的测试点没过,可能就是因为输出错误而已。这时我们只需要检查一下我们的输出格式即可。
3.当涉及到多个if-else语句时,千万要仔细,(其实我在这里建议大家,在可以不用太多if-else语句时可以不用,把它换成别的语句实现)因为这个语句,可能再有的时候进行的判断与我们所想象的不同,给出的结果也不经如人意
4.最后一点,当遇到某个点实在无法通过时,可以去问老师或者是去问问同学,因为,可能是自己写的代码,无法轻易就观察到自己的错误,而老师就不一样了,他拥有的知识面更广,肯定能找出我们的错误,当然也可以上百度上搜索相应的问题,在其中,还能学到一些新的知识点,(这里借用高数老师的一句话:知识不问来路,学问不问出处)学到了才是真本身
改进建议:
改进建议的话,其实就这三次题目集来讲,并无什么特别需要改进的地方,如果有问题的话,那也是我们自己对于类的关系的不理解,经过如此长时间的的授课,相信我们的编程能力,已经可以达到我们所要的需求了,就算接下来就是对于整体问题的思考,这种思考的能力,并不是老师可以教授给我们的,要锻炼这种能力,只能靠我们自己,多看书,多刷题。遇到不会的问题,多去找找老师,请教他。相信这样我们只会越来越进步而已!
总结
经过这三次的题目集,我们对于Java这门语言又有了新的认识,原来类之间的关系这门精细的嘛,还有我们对于类与类之间的关系的了解更上了一层楼,无论是题目集7的图形类设计,还是题目集8与题目集9 的ATM机的设计,都用到了我们的依赖、聚合、组合的关系,到底它的类的出现形式是怎样的呢,是作为属性出现在另一个类中以供调用还是,只是在方法体中使用了一下它其中的一个属性,对于ATM机的设计中,我就Account与Card和Bank的类的关系思考了许久,到底它们是什么关系,我用了哪关系,能够更好的解决我所需要的解决的问题呢。这个使的我思考了许久……
后面经过对于实际生活中对于银行的了解,了解它们的账户之类的关系,人对于Bank类和Account类以及Card类的关系。类一多,那么关系就复杂了,就很难理清楚。经过这几次的实验,或许可以说是磨练。那么我们对于后面的实验就有了一定的接受能力,就算后面的实验再难,也还是在可接受的范围内的。
这次课程结束,我们不仅学会了专业的技术,更是锻炼了我们的心态,及时碰到了很多很难解决问题,经过多方打磨,也还是能解决的!!!