Java第二次总结
随着学习Java已经过去两个月了,在学习过程中也产生了很多与以往不同的心得,下面对这两周作业中遇到的问题及心得体会做一下总结。
第一部分:农夫过河问题总结
在过去的两周内,布置了一次农夫过河实验,其中有两次作业,分别是抽象类的使用与接口的使用,下面就对其做一下总结。
农夫过河--抽象类的使用
Task:
1、 掌握Java语言中final关键字的含义及使用方法;
2、 掌握Java语言中抽象类的基本概念及使用方法;
3、以题目所给类图为基础,重构实验二中农夫过河游戏的代码。
设计策略:根据题目所给的类图,增加几个抽象类,增加一个抽象物品类,再创建一个Animal动物类,Person类以及Plant植物类,让他们都继承抽象物品类。增加一个抽象交通工具类,创建一个Boat船类,继承抽象交通工具类,负责承载物品过河。增加一个抽象规则类,负责游戏中的规则,创建负责判断物品是否存在、游戏是否结束、游戏输赢、物品是否过河的几个类继承抽象游戏规则类。增加一个抽象游戏类,让负责控制控制作用的Game游戏类继承抽象游戏类,再创建一个负责游戏界面作用的GameUI类继承抽象游戏类。
类图如下:
Game类代码如下:
import java.util.Scanner;
public class Game extends AbstractGame {
private AbstractRule gameOverRule = new GameOverRule();
private AbstractRule gameSuccessRule = new GameSuccessRule();
private GameData gamedata = new GameData();
@Override
public void play() {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
int choice = 0; //用户输入选择进
boolean gameOver=false,//游戏结束标志,默认为false,代表游戏进行中,未结束
while(!gameOver)
{
Game game = new Game();
GameUI.menu();
choice = input.nextInt();
switch(choice)
{
case 0: gameOver=true;
break;
case 1:/* 农夫独自过河的处理 */
gamedata.getBoat().crossRiver(gamedata.farmer);
break;
case 2:/* 农夫带狼的处理 */
gamedata.getBoat().crossRiver(gamedata.farmer, gamedata.wolf);
break;
case 3:/* 农夫带羊的处理 */
gamedata.getBoat().crossRiver(gamedata.farmer, gamedata.sheep);
break;
case 4:/* 农夫带白菜的处理 */
gamedata.getBoat().crossRiver(gamedata.farmer, gamedata.cabbage);
break;
}
if(gamedata.wolf.canBeEat(gamedata.sheep, gamedata.farmer)) {
gamedata.sheep.diedOut();
}else if(gamedata.sheep.canBeEat(gamedata.cabbage, gamedata.farmer)) {
gamedata.cabbage.diedOut();
}
GameUI.showStatus(gamedata);
gameOver = gameOverRule.judge(gamedata.farmer, gamedata.wolf, gamedata.sheep, gamedata.cabbage);
}
if(gameSuccessRule.judge(gamedata.farmer, gamedata.wolf, gamedata.sheep, gamedata.cabbage)) {
System.out.println("game over: you win !");
}else {
System.out.println("game over: you lose !");
}
input.close(); }
}
代码分析:这一段代码是在之前写的农夫过河Game类代码的基础上修改的,基本功能差不多,只不过实现形式由原来的直接调用实体类方法变为现在通过抽象类的部分方法实现。
优点:运用抽象类,隐藏了代码的部分细节信息。对比前几次的农夫过河实验,这次的类设计大大增加,使每一个类都有自己的作用,实现的单依职责原则,大大降低了耦合性,使程序可扩展性也大大增加。
缺点:在写此次实验的过程中,因为类设计过于复杂,在开始时思路有些混乱,代码中没有很好的体现每一个类应有的功能。但在后期不断改善,修复的过程中,使每一个类的功能尽可能的完善了起来。
农夫过河——接口的使用
Task: 在实验4-1的基础上新增一个高兴Happy和哭泣Cry接口,农夫、狼、羊实现Happy接口,农夫在成功渡河、狼在吃羊、羊吃白菜的时候执行高兴接口方法,通过控制台输出不同的内容(内容可自定义,但三观要正)。羊、白菜实现Cry接口,当羊和白菜被吃的时候会用自己的方式哭泣并在控制台输出。
设计策略:在上次的基础上增加几个实体类,将Sheep类、Wolf类继承Animal类,将Cabbage类继承Plant类,使他们能够更方便实现接口。创建两个接口类Happy类与Cry类,在实体类里实现输出方法,并在GameUI类里通过判断条件来输出接口类的实现方法。
类图如下:
GameUI类代码如下:
public class GameUI {
public static void menu() {
/* 显示菜单 */
System.out.println("==================Please choose operation============");
System.out.println("\t==========1:Cross the river alone===========");
System.out.println("\t==========2:Cross the river with wolf=========");
System.out.println("\t==========3:Cross the river with sheep============");
System.out.println("\t==========4:Cross the river with cabbage==========");
System.out.println("\t==========0:Quit===============");
System.out.println("===================================================");
System.out.println("Input the number(0~4):");
}
public static void showStatus(GameData gamedata) {
/* 显示每种物品状态 */
gamedata.farmer.showStatus(gamedata.farmer);
if(gamedata.farmer.place) {
gamedata.farmer.showHappy();
}
gamedata.wolf.showStatus(gamedata.wolf);
if(gamedata.wolf.canBeEat(gamedata.sheep, gamedata.farmer)) {
gamedata.wolf.showHappy();
}
gamedata.sheep.showStatus(gamedata.sheep);
if(gamedata.sheep.canBeEat(gamedata.cabbage, gamedata.farmer)) {
gamedata.sheep.showHappy();
}
if(!gamedata.sheep.isExist()) {
gamedata.sheep.showCry();
}
gamedata.cabbage.showStatus(gamedata.cabbage);
if(!gamedata.cabbage.isExist()) {
gamedata.cabbage.showCry();
}
}}
代码分析:通过这个GameUI类中的showStatus方法来增加判断是否输出实现接口的方法,如果狼与羊在同一边且不与农夫在一边则实现接口方法,输出字符串。
优点:通过增加接口类,增加了代码的复杂度,使游戏体验感更高。
缺点:在每个实体类里都实现接口,过程过于复杂,同时耦合性也比较高,有待改进。
第二部分:期中考试总结
第一题:7-1 点与线(类设计)
Task:设计一个类表示平面直角坐标系上的点Point,私有属性分别为横坐标x与纵坐标y,数据类型均为实型数,除构造方法以及属性的getter与setter方法外,定义一个用于显示信息的方法display(),用来输出该坐标点的坐标信息,格式如下:(x,y)
,数值保留两位小数。为简化题目,其中,坐标点的取值范围设定为(0,200]
。若输入有误,系统则直接输出Wrong Format
设计一个类表示平面直角坐标系上的线Line,私有属性除了标识线段两端的点point1、point2外,还有一个字符串类型的color,用于表示该线段的颜色,同样,除构造方法以及属性的getter与setter方法外,定义一个用于计算该线段长度的方法getDistance(),还有一个用于显示信息的方法display(),用来输出线段的相关信息。
设计策略:按照题目所给要求,设计三个类,一个主类,一个Point类,一个Line类,Point类负责输出点,Line类负责计算线段。
类图如下:
Main类代码如下:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
double x1 = input.nextDouble();
double y1 = input.nextDouble();
double x2 = input.nextDouble();
double y2 = input.nextDouble();
Point p1 = new Point(x1,y1);
Point p2 = new Point(x2,y2);
String color = input.next();
Line line = new Line(p1,p2,color) ;
if(x1<=0 || x1>200||x2<=0 || x2>200||y1<=0 || y1>200||y2<=0 || y2>200) {
System.out.println("Wrong Format");
System.exit(0);
}
System.out.println("The line's color is:" + line.getColor());
System.out.println("The line's begin point's Coordinate is:");
p1.display();
System.out.println("The line's end point's Coordinate is:");
p2.display();
line.display();
}
}
优点:代码实现了开闭原则,使每一个类的功能都能很好的体现,降低了代码的耦合性,提高了程序的可扩展性。
缺点:开始时没有很快的分析好题目要求,所以在第一题上花了不少时间。
第二题:7-2 点线面问题重构(继承与多态)
Task:
在“点与线(类设计)”题目基础上,对题目的类设计进行重构,以实现继承与多态的技术性需求。
对题目中的点Point类和线Line类进行进一步抽象,定义一个两个类的共同父类Element(抽象类),将display()方法在该方法中进行声明(抽象方法),将Point类和Line类作为该类的子类。再定义一个Element类的子类面Plane,该类只有一个私有属性颜色color,除了构造方法和属性的getter、setter方法外,display()方法用于输出面的颜色,输出格式如下:The Plane's color is:颜色
在主方法内,定义两个Point(线段的起点和终点)对象、一个Line对象和一个Plane对象,依次从键盘输入两个Point对象的起点、终点坐标和颜色值(Line对象和Plane对象颜色相同),然后定义一个Element类的引用,分别使用该引用调用以上四个对象的display()方法,从而实现多态特性。
设计策略:按照题目要求,增加一个Element类作为父类,让Point类,Line类继承自Element类,同时实现多态功能。
类图如下:
多态部分代码:
element = p1;//起点Point
element.display();
element = p2;//终点Point
element.display();
element = line;//线段
element.display();
element = plane;//面
element.display();
优点:通过继承与多态的使用,提高了代码的复用性与可维护性。
心得:在这一题中,因为直接用了题目所给的多态部分的代码,节省了很多做题时间,同时也要学习题目所给的多态部分代码,运用到自己代码的使用中。
第三题:7-3 点线面问题再重构(容器类)
Task:在“点与线(继承与多态)”题目基础上,对题目的类设计进行重构,增加容器类保存点、线、面对象,并对该容器进行相应增、删、遍历操作。
在原有类设计的基础上,增加一个GeometryObject容器类,其属性为ArrayList<Element>
类型的对象(若不了解泛型,可以不使用<Element>
)增加该类的add()
方法及remove(int index)
方法,其功能分别为向容器中增加对象及删除第index - 1
(ArrayList中index>=0)个对象
设计策略:按照题目所给要求增加一个GeometryObject容器类,通过容器来增加与删除Point对象、Line对象与Plane对象。
类图如下:
Main类与GeometryObject类代码如下:
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner input = new Scanner(System.in);
GeometryObject add = new GeometryObject();
int choice = input.nextInt();
while(choice != 0) {
switch(choice) {
case 1://insert Point object into list
Element point = new Point(input.nextDouble(),input.nextDouble());
add.getList().add(point);
point.display();
break;
case 2://insert Line object into list
Point p1 = new Point(input.nextDouble(),input.nextDouble());
Point p2 = new Point(input.nextDouble(),input.nextDouble());
String color = input.next();
Line line = new Line(p1,p2,color);
add.getList().add(line);
System.out.println("The line's color is:" + line.getColor());
System.out.println("The line's begin point's Coordinate is:");
p1.display();
System.out.println("The line's end point's Coordinate is:");
p2.display();
break;
case 3://insert Plane object into list
String color2 = input.next();
Plane plane = new Plane(color2);
add.getList().add(plane);
plane.display();
break;
case 4://delete index - 1 object from list
int index = input.nextInt();
if(index>add.getList().size() || index < 1) {
break;
}
add.getList().remove(index - 1);
break;
}
choice = input.nextInt();
} }
}
class GeometryObject {
private ArrayList<Element> list = new ArrayList<Element>(); public void add() {
}
public void remove(int index) {
} public ArrayList<Element> getList() {
return list;
} public void setList(ArrayList<Element> list) {
this.list = list;
}
}
优点:通过ArrayList的使用,增加了代码的可复用性与可扩展性
心得:在第三题的写题过程中,出现了很多bug,开始时不清楚list自身就有remove方法,在主类中也出现了很多逻辑上的错误,虽然都是很小的错误,但也debug了不少时间,导致后期时间不够用。在以后的做题中尽量增加逻辑性与细心度,避免不必要的逻辑性错误。