展开全部
这是个挺有趣的问题,我们可以一起来分析下:
1.这里面只有两32313133353236313431303231363533e59b9ee7ad9431333335343961个类,武器类和怪兽类;而动作只有一个,打。
2.面向对象的思想是为类分配职责,那么打这个动作到底分配给谁?
很明显应该分配给怪兽类,因为打这个动作涉及的大部分数据都是怪兽类包含的,从常识上来讲分配给武器类感觉怪怪的...
3.从上面可以想象到会出现这样的情况monster.hit(otherMonster),这里monster是打,otherMonster是被打。hit方法里面需要将otherMonster的信息获取出来,然后计算打的过程...这样会把otherMonster的数据封装破坏掉,如果扩展otherMonster,显然你必需要在hit方法里判断otherMonster是哪种类型。但是monster.hit(otherMonster)又是符合对象的思维的。那么问题出在哪里?
问题出在打是一个动词,打这个方法分配给了一个对象,但作用的是另一个对象,因此而破坏了数据封装。如果打分配给一个对象,同时作用的是这个对象,那么问题就解决了。
怎样把打分配给一个对象,同时作用的是这个对象呢?答案是把打转换成被打,于是就成了otherMonster.hit(),在monster需要去打otherMonster时,调用otherMonster.hit()就可以了。
4.武器类还没有被引入进来,明显武器不会自动攻击,他必须装备在monster上,我们可以把weapon作为monster的成员。
5.武器类可以被使用在打这个动作上,于是我们为hit方法增加武器参数,于是就变成otherMonster.hit(weapon),这个方法是在monster内部调用的,weapon也是monster的成员,没有破坏封装性。
6.至此,你提的这个问题就是这样了...class Monster{
private Weapon weapon;
public void hit(Weapon weapon){
//dosometing.
}
public Weapon getWeapon(){
return weapon;
}
public void setWeapon(Weapon weapon){
this.weapon = weapon;
}
}
是不是感觉怪怪的...我们可以继续来探讨这个问题:
为什么感觉怪怪的?是因为这个问题太简化了,简化到我们并不知道Monster被打之后到底发生什么。
感觉这个很像个游戏,大部分游戏都是基于hitpoint(血量)的,为了使这个问题带感一些,我们给Monster一个int类型的hitPoint。
同时给武器类赋予一个attackPoint,在Monster被打的时候扣除attackPoint数量的hitPoint。
那么问题来了,hit方法里需要获取Weapon中的attackPoint,这又会把Weapon的数据封装破坏掉...
为此我们需要给Monster一个直接扣除hitPoint的方法damage(int attackPoint),让Weapon能够调用damage方法把自身的attackPoint传递进来。
Weapon本身我们可以分配一个attack(Monster monster)方法来给Monster把自身传递进来,于是程序就变成了:class Monster{
private Weapon weapon;
private int hitPoint;
public void hit(Weapon weapon){
weapon.attack(this);
}
public void damage(int attackPoint){
this.hitPoint -= attackPoint;
}
public Weapon getWeapon(){
return weapon;
}
public void setWeapon(Weapon weapon){
this.weapon = weapon;
}
}
class Weapon{
private int attackPoint;
public void attack(Monster monster){
monster.damage(attackPoint);
}
}
也许有人会问,hit里面调用weapon.attack,attack里面又调用monster.damage,那还不如在hit里直接获取weapon的attackPoint,然后直接扣除hitPoint。
为什么要这么麻烦呢?实际上这里Weapon是一个策略(Strategy模式),由策略来决定对对象到底采取什么样的作用。这里感觉麻烦也是因为问题太简单了。
再带感一点,我们参考网游的做法,Monster本身有一定的躲避和格挡率,同时某些Weapon可能会有暴击率:
此时我们需要在hit方法里先计算是否躲避或者格挡,如果都不成功,才调用weapon.attack(this).在attack方法里,需要先计算是否暴击,如果暴击,则把attackPoint乘以2。于是又变成了class Monster{
private Weapon weapon;
private int hitPoint;
private int dodge;//100%比例
private int block;//100%比例
public void hit(Weapon weapon){
if (isDodge()){
return;
}
if (isBlock){
return;
}
weapon.attack(this);
}
public void damage(int attackPoint){
this.hitPoint -= attackPoint;
}
public boolean isDodge(){
//COMPUTE IS DODGE?
}
public boolean isBlock(){
//COMPUTE IS BLOCK?
}
public Weapon getWeapon(){
return weapon;
}
public void setWeapon(Weapon weapon){
this.weapon = weapon;
}
}
class Weapon{
private int attackPoint;
private int critical;//100%比例
public void attack(Monster monster){
int actualAttackPoint = isCritical()?attackPoint*2:attackPoint;
monster.damage(actualAttackPoint);
}
public boolean isCritical(){
//COMPUTE IS CRITICAL
}
}
这样就不觉得麻烦了...
最后应该把monster抽象成接口,因为可能不只是monster可以被武器打哦
你还可以后面再加入怎么判断Monster挂了,通过观察者模式来通知打人者,还有其他各种各样带感的东西。
祝你好运!