【在这一节里,我将给扩展我们的Person类,引入这个实例的主角:武器。】
常常想,如果没有客户该多好,我们的设计就不用因为这多变的需求变得面目全非了。 可是需求的变化是无法避免的,变化才是永恒的主旋律。现实世界如此,做为现实世界投影的业务世界当然也是如此。即便是在这个没有客户的实例中,我们追求完美的一面就负担着客户的角色,不停的给我们的设计带来变化。所以我的思维现在应该一分为二:一部分扮演“客户”,另一部分扮演“程序员”。这对我不是很难,人家都说双鱼座的人有一点双重性格嘛^_^。
我们假设现在这个项目提交给“客户”了。
-----------
客户:嗯,这符合我的要求,不过(程序员心说:我们都怕这个)能不能输出每一回合被攻击的人掉了多少HP?
程序员:这不难,你要按什么格式输出?
客户:就按“张三攻击了李四,李四受到XX点伤害,李四剩余生命:XX”这个格式吧。
-----------
新的需求,好吧,我们来扩展,修改Person类
... {
int damage = this.offense - target.defense;
target.hp -= damage;
//开始输出
System.out.print(this.name);
System.out.print("攻击了");
System.out.print(target.getName());
System.out.print(",");
System.out.print(target.getName());
System.out.print("受到了");
System.out.print(damage);
System.out.print("点伤害");
System.out.print(target.getName());
System.out.print("剩余生命:");
System.out.println(target.hp);
}
修改完毕后,我们继续运行Game类的main方法,结果如下:
......(前面省略若干行)
李四攻击了张三,张三受到了4点伤害张三剩余生命:24
张三攻击了李四,李四受到了4点伤害李四剩余生命:20
李四攻击了张三,张三受到了4点伤害张三剩余生命:20
张三攻击了李四,李四受到了4点伤害李四剩余生命:16
李四攻击了张三,张三受到了4点伤害张三剩余生命:16
张三攻击了李四,李四受到了4点伤害李四剩余生命:12
李四攻击了张三,张三受到了4点伤害张三剩余生命:12
张三攻击了李四,李四受到了4点伤害李四剩余生命:8
李四攻击了张三,张三受到了4点伤害张三剩余生命:8
张三攻击了李四,李四受到了4点伤害李四剩余生命:4
李四攻击了张三,张三受到了4点伤害张三剩余生命:4
张三攻击了李四,李四受到了4点伤害李四剩余生命:0
李四被打败了
Ok,我们的程序写完了。交给客户,客户又说了:“加入点武器是不是更好一些呢,让玩家装备武器,武器的攻击力加到用户的攻击力上,攻击的时候输出‘张三用OO(武器)攻击了李四”。
程序说:“......好吧。”(有一种不祥的预感)
首先修改Game
... {
Person p1 = new Person(100, 10, 5);
Person p2 = new Person(100, 9, 6);
p1.setName("张三");
p2.setName("李四");
//装备武器
Weapon normal = new Weapon(4);
Weapon excellence = new Weapon(5);
normal.setName("普通木棍");
excellence.setName("优质木棍");
p1.setWeapon(normal);
p2.setWeapon(excellence);
while (p1.alive() && p2.alive())
...{
// 这个玩法不太公平,不过这不是问题的关键
p1.attack(p2);
if (p2.alive())
...{
p2.attack(p1);
}
}
showWinner(p1,p2);
}
从这个main方法的修改版可以看出我们需要一个Weapon类和一系列新的方法和域。所以我们添加Weapon如下:
... {
public Weapon(int offense)
...{
this.offense = offense;
}
public int getOffense()
...{
return offense;
}
public void setName(String name)
...{
this.name = name;
}
public String getName()
...{
return this.name;
}
private int offense;
private String name;
}
... {
//下面这行代码被修改
int damage = this.offense + this.weapon.getOffense() - target.defense;
target.hp -= damage;
System.out.print(this.name);
//修改在这里
System.out.print("用");
System.out.print(this.weapon.getName());
//修改完毕
System.out.print("攻击了");
System.out.print(target.getName());
System.out.print(",");
System.out.print(target.getName());
System.out.print("受到了");
System.out.print(damage);
System.out.print("点伤害");
System.out.print(target.getName());
System.out.print("剩余生命:");
System.out.println(target.hp);
}
好的,我们运行Game的main方法,输出结果:
(前面省略若干行)
张三用普通木棍攻击了李四,李四受到了8点伤害李四剩余生命:12
李四用优质木棍攻击了张三,张三受到了9点伤害张三剩余生命:1
张三用普通木棍攻击了李四,李四受到了8点伤害李四剩余生命:4
李四用优质木棍攻击了张三,张三受到了9点伤害张三剩余生命:-8
张三被打败了
很好,很好。这一切都是那么的简单。我们很轻易得就走到了现在,赶紧去提交给客户,客户看了非常满意,以至于他的想象开始乱窜。。。。。
客户:这太好了,不过......这个武器系统好像太单调了(程序员:“天知道这家伙从哪里学来得武器系统这个该死的新名词。”)。我们应该给我们每一种武器各自特性,比如致晕,致残,中毒。要随机的引发这些特性,嗯,最好加入一些运气的成分,对了,武器似乎也是没有距离之分,应该让长兵器的占点便宜,不过这又对短兵器不公平了,那就给短兵器一些特有的附加效果,这个我得在想想,你先去做吧。
程序员:果然,.......(狂晕)
他这一席话可好,我们前面做的很多东西都要推翻了重做了。所以每当碰到这种情况的时候,我们常用的一种手法是:“讨价还价”。这个有问题啊,那个有难度啦,时间不够了啊。总之能删则删,能减则减。不过互相通过优秀的公关手法和交涉手法交手之后,我们有些能逃掉,有些则逃不掉。甚至有些东西是根植于客观规律中的,即便客户松口不让我们做了,但是我们最终还是不得不实现。不过在这个例子中,这是一个好现象,如果没有稍微复杂点的需求,怎么会理解OO的优势所在呢?怎么会理解脱耦的方便呢?所以我们继续,完成“客户”的需求。
(待续......)