案例题目:
用面向对象的思想完成
根据给定的题目进行分析:
1、 首先我们考虑需要几个类来实现,
2、 在这几个设定的类中有没有可能出现抽象类
3、 有没有出现接口来实现内容
我们可以初步判断三个类和一个主程序是显示易见的。
A、玩家类 :与电脑比拼的人
B、电脑类 :参与游戏的智能机器人
C、游戏类:电脑和玩家工作的平台
D、主程序调用
接着再分析这几个类有哪些方法和属性
玩家类哪些行为、属性:
根据给定的题目,很显然可以获得name和score属性。
name:玩家的名字
score:玩家的总分
方法:
出拳:给出猜拳的数字
电脑类也很显示会出现同样的属性和方法:
属性。
name:玩家的名字
score:玩家的总分
方法:
出拳:给出猜拳的数字
这样电脑类和玩家类都有同样的属性和方法,我们可以做出以下考虑:
1、 可不可以有一个共同的父类为他们服务
2、 父类可不可以出现共同的方法和属性
3、 父类的方法中有没有子类可能重用的代码
这样可以决定父类需不需要做成抽象类,不允许去new ,只能子类继承再去使用。
我们可以暂时考虑一下电脑和玩害对猜拳代码的写法:
电脑类:
ch=随机数产生1,2,3
Switch(ch)
case 1:
println(name+“出拳:剪刀”);break;
case 2:
println(name+“出拳:石头”);break;
case 3:
println(name+“出拳:布”);break;
玩家类:
ch=用户输入的数值
Switch(ch)
case 1:
println(name+“出拳:剪刀”);break;
case 2:
println(name+“出拳:石头”);break;
case 3:
println(name+“出拳:布”);break;
由上面两个类代码的大概样子,就可以得出他们是有重复代码的,完全可以通过父类完成重复代码的编写,再通过子类继承过来实现重写来完成子类需要的功能。
当父类的方法在子类中被重写时,很有可能在以后的编程过程中会同现多态的情况。这样也有利于代码的扩展。引用父类或者引用子类。既然有多态的多现,就使得父类不能成为抽象类,需要可以new来实现的。
这样设计中就出现了多态的情况。
电脑类、玩家类
多态技术引入会给我们带来扩展的方便。
再加入玩家没有问题。
选手类可以new
比如cuquan(XuanShou xs);就可以实现
cuquan(new 电脑类());
cuquan(new 玩家类());
在程序体中就可以
xs.出拳
一个函数就完成了电脑的出拳和玩家的出拳。
再则,游戏类的考虑:
只要我们想做游戏类,必然包含对游戏的初始化,开始游戏,判断游戏,结束游戏。这些过程是必不可少的。为了更好的规划方法,把游戏类做成接口,限定开发者的方法名称,有利于更合理地去进行代码管理。
因此游戏类可以做成接口.
通过以上的分析
基本结论:
1、 三个类:选手类、玩家类、电脑类
都可以new,有多态的发生
2、 游戏类:扩大化,统一规范变成接口Game
初始化init()实现的功能。New类player compute;
开始游戏:start();
游戏判定:judge();
游戏结束: end();
三个类一个接口
三个类:Athlete Computer Player
一个接口:Game
分析结束后,现在我们实现代码:
选手类:Athlete类
先做两个私有成员变量
对这两个成员变量做getter setter方法:
点击菜单:Source--àGenerater Getters and Setters
就会出现对变量的选择,在两个变量上打勾:
OK后,就可以实现私有变量的getter和setter方法
再对Athlete做构造方法,有参与无参:
先做有参:点击ecllipse--àGenerater Constructor using Fields
出现选择的成员变量名,选择后,OK
有参构造函数成功。
拷贝产生无参构造函数:
为了防止此类实例对象打印不是一个堆内存地址,重写toString方法.
点击Ecllipse--àGenerate toString()
就会产生toString方法的自动重写函数:
然后我们可以写父类的chuquan()函数.在写函数里出现了switch(ch) ,ch 做为变量,我们如何接收,如果传参,在参数中接收,游戏类在调用这个方法时就会传参。会出现了游戏类和电脑类、玩家类之间的一种耦合关系,这种耦合也不利于游戏玩家的扩展。再添加玩家又需要游戏类处理,这样很麻烦,失去了继承后代码重用的好处。不能做参数,在类中只能做成员变量,于是成员变量就多了一个ch.
做成员变量ch的setter和getter方法:
有了ch的成员变量,Athlete的chuquan方法就有了这样的代码体:
Computer Player继承Athlete,重写出拳方法chuqu()
Super.chuquan()放在重写代码的下面
于是Player类的重写方法为:
然后实现两个类初始化的名字输入,写入代码体:
电脑类:
玩家类:
玩家类和电脑类基本完成。
游戏接口类:直接定义接口,然后在其中限定抽象方法:
新建TestGame类,实现这个接口:
TestGame类报错,需要重写定义的抽象方法:
上图是重写展示的部分代码。
对这五个方法重写,需要游戏中的两个主角全程参与,player和computer就是这成为这个类的成员变量了解。
也就是说TestGame类,重写方法的时候增加两个成员变量
因为每个方法都用同一个对象
Player player=new Player()
Computer comp=new Computer()
在游戏类的构造函数中设置代码块,目的是对游戏进行说明性文档和用户的警示语。
接着实现游戏类的init方法:
将玩家进行new,将电脑进行new
根据游戏流程的提示:
这里的game_continue()方法是按照游戏流程,询问用户是否继续游戏:
从流程代码中看,当用户输入y即进入到start()方法,即游戏开始的方法:
从游戏流程上看,在玩家出拳和电脑出拳后进入到judge环节:即判断胜负
剪刀石头布判断胜负可从以下三种方法中实现。
(1) 穷举法:
我们假定1为赢,-1为输,0为平局
玩家 剪刀 石头 布
电脑 石头(1) 剪刀(-1) 剪刀(1)
布(-1) 布(1) 石头(-1)
剪刀:(0) 石头(0) 布(0)
这样代码变成:
(2) 二维数组法:
把剪刀、石头、布三项看成行和列的三项,玩家为行,电脑为列,赢了为1,平局为0,输了为-1,构成的二维数组如下:
剪刀 石头 布
剪刀 0 -1 1
石头 1 0 -1
布 -1 1 0
行:玩家 列:电脑
Int[] arr={{0,-1,1},{1,0,-1},{-1,1,0}}
这样二维数组的代码为:
(3)减值规律法
剪刀石头 布
1 2 3
Player computer
赢的情况:Player-comuter==1||player-computer==-2
输的情况:player-computer=-1||player-computer==2
其它情况:平局
于是代码就变成了。
根据程序输出的具体流程,玩家赢了还需要对总分进行统计,电脑赢了也需要对总分进行统计。对总分进行统计的方法都是取出总分,然后进行加值操作,玩家和电脑都继承于选手类,所以可以使用多态的方法。
然后在judge里面调用此方法:
最后进行end()结束方法的调用,因为有比赛次数的统计,所以加入一个成员变量sum;
根据game_continue()里面对sum的判断决定是否运行到end()结束方法中:
最后在end()方法中输出sum的比赛次数和最终比较的结果:
最后建立主程序类MainGame,运行主程序
至此,剪刀石头布面向对象程序基本雏形制作完毕.
代码的github地址:https://github.com/wawacode/java_stone-scissors-cloth