小李打妖怪.docx
- 文档编号:10498985
- 上传时间:2023-02-14
- 格式:DOCX
- 页数:19
- 大小:110.37KB
小李打妖怪.docx
《小李打妖怪.docx》由会员分享,可在线阅读,更多相关《小李打妖怪.docx(19页珍藏版)》请在冰豆网上搜索。
小李打妖怪
1IGame游戏公司的故事
1.1讨论会
话说有一个叫IGame的游戏公司,正在开发一款ARPG游戏(动作&角色扮演类游戏,如魔兽世界、梦幻西游这一类的游戏)。
一般这类游戏都有一个基本的功能,就是打怪(玩家攻击怪物,借此获得经验、虚拟货币和虚拟装备),并且根据玩家角色所装备的武器不同,攻击效果也不同。
这天,IGame公司的开发小组正在开会对打怪功能中的某一个功能点如何实现进行讨论,他们面前的大屏幕上是这样一份需求描述的ppt
图1.1需求描述ppt
各个开发人员,面对这份需求,展开了热烈的讨论,下面我们看看讨论会上都发生了什么。
1.2实习生小李的实现方式
在经过一番讨论后,项目组长Peter觉得有必要整理一下各方的意见,他首先询问小李的看法。
小李是某学校计算机系大三学生,对游戏开发特别感兴趣,目前是IGame公司的一名实习生。
经过短暂的思考,小李阐述了自己的意见:
“我认为,这个需求可以这么实现。
HP当然是怪物的一个属性成员,而武器是角色的一个属性成员,类型可以使字符串,用于描述目前角色所装备的武器。
角色类有一个攻击方法,以被攻击怪物为参数,当实施一次攻击时,攻击方法被调用,而这个方法首先判断当前角色装备了什么武器,然后据此对被攻击怪物的HP进行操作,以产生不同效果。
”
而在阐述完后,小李也飞快的在自己的电脑上写了一个Demo,来演示他的想法,Demo代码如下。
Code:
怪物
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLi
7:
{
8:
///
9:
///怪物
10:
///
11:
internalsealedclassMonster
12:
{
13:
///
14:
///怪物的名字
15:
///
16:
publicStringName{get;set;}
17:
18:
///
19:
///怪物的生命值
20:
///
21:
publicInt32HP{get;set;}
22:
23:
publicMonster(Stringname,Int32hp)
24:
{
25:
this.Name=name;
26:
this.HP=hp;
27:
}
28:
}
29:
}
Code:
角色
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLi
7:
{
8:
///
9:
///角色
10:
///
11:
internalsealedclassRole
12:
{
13:
privateRandom_random=newRandom();
14:
15:
///
16:
///表示角色目前所持武器的字符串
17:
///
18:
publicStringWeaponTag{get;set;}
19:
20:
///
21:
///攻击怪物
22:
///
23:
///
24:
publicvoidAttack(Monstermonster)
25:
{
26:
if(monster.HP<=0)
27:
{
28:
Console.WriteLine("此怪物已死");
29:
return;
30:
}
31:
32:
if("WoodSword"==this.WeaponTag)
33:
{
34:
monster.HP-=20;
35:
if(monster.HP<=0)
36:
{
37:
Console.WriteLine("攻击成功!
怪物"+monster.Name+"已死亡");
38:
}
39:
else
40:
{
41:
Console.WriteLine("攻击成功!
怪物"+monster.Name+"损失20HP");
42:
}
43:
}
44:
elseif("IronSword"==this.WeaponTag)
45:
{
46:
monster.HP-=50;
47:
if(monster.HP<=0)
48:
{
49:
Console.WriteLine("攻击成功!
怪物"+monster.Name+"已死亡");
50:
}
51:
else
52:
{
53:
Console.WriteLine("攻击成功!
怪物"+monster.Name+"损失50HP");
54:
}
55:
}
56:
elseif("MagicSword"==this.WeaponTag)
57:
{
58:
Int32loss=(_random.NextDouble()<0.5)?
100:
200;
59:
monster.HP-=loss;
60:
if(200==loss)
61:
{
62:
Console.WriteLine("出现暴击!
!
!
");
63:
}
64:
65:
if(monster.HP<=0)
66:
{
67:
Console.WriteLine("攻击成功!
怪物"+monster.Name+"已死亡");
68:
}
69:
else
70:
{
71:
Console.WriteLine("攻击成功!
怪物"+monster.Name+"损失"+loss+"HP");
72:
}
73:
}
74:
else
75:
{
76:
Console.WriteLine("角色手里没有武器,无法攻击!
");
77:
}
78:
}
79:
}
80:
}
Code:
测试代码
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLi
7:
{
8:
classProgram
9:
{
10:
staticvoidMain(string[]args)
11:
{
12:
//生成怪物
13:
Monstermonster1=newMonster("小怪A",50);
14:
Monstermonster2=newMonster("小怪B",50);
15:
Monstermonster3=newMonster("关主",200);
16:
Monstermonster4=newMonster("最终Boss",1000);
17:
18:
//生成角色
19:
Rolerole=newRole();
20:
21:
//木剑攻击
22:
role.WeaponTag="WoodSword";
23:
role.Attack(monster1);
24:
25:
//铁剑攻击
26:
role.WeaponTag="IronSword";
27:
role.Attack(monster2);
28:
role.Attack(monster3);
29:
30:
//魔剑攻击
31:
role.WeaponTag="MagicSword";
32:
role.Attack(monster3);
33:
role.Attack(monster4);
34:
role.Attack(monster4);
35:
role.Attack(monster4);
36:
role.Attack(monster4);
37:
role.Attack(monster4);
38:
39:
Console.ReadLine();
40:
}
41:
}
42:
}
程序运行结果如下:
图1.2小李程序的运行结果
1.3架构师的建议
小李阐述完自己的想法并演示了Demo后,项目组长Peter首先肯定了小李的思考能力、编程能力以及初步的面向对象分析与设计的思想,并承认小李的程序正确完成了需求中的功能。
但同时,Peter也指出小李的设计存在一些问题,他请小于讲一下自己的看法。
小于是一名有五年软件架构经验的架构师,对软件架构、设计模式和面向对象思想有较深入的认识。
他向Peter点了点头,发表了自己的看法:
“小李的思考能力是不错的,有着基本的面向对象分析设计能力,并且程序正确完成了所需要的功能。
不过,这里我想从架构角度,简要说一下我认为这个设计中存在的问题。
首先,小李设计的Role类的Attack方法很长,并且方法中有一个冗长的if…else结构,且每个分支的代码的业务逻辑很相似,只是很少的地方不同。
再者,我认为这个设计比较大的一个问题是,违反了OCP原则。
在这个设计中,如果以后我们增加一个新的武器,如倚天剑,每次攻击损失500HP,那么,我们就要打开Role,修改Attack方法。
而我们的代码应该是对修改关闭的,当有新武器加入的时候,应该使用扩展完成,避免修改已有代码。
一般来说,当一个方法里面出现冗长的if…else或switch…case结构,且每个分支代码业务相似时,往往预示这里应该引入多态性来解决问题。
而这里,如果把不同武器攻击看成一个策略,那么引入策略模式(StrategyPattern)是明智的选择。
最后说一个小的问题,被攻击后,减HP、死亡判断等都是怪物的职责,这里放在Role中有些不当。
”
Tip:
OCP原则,即开放关闭原则,指设计应该对扩展开放,对修改关闭。
Tip:
策略模式,英文名StrategyPattern,指定义算法族,分别封装起来,让他们之间可以相互替换,此模式使得算法的变化独立于客户。
小于边说,边画了一幅UML类图,用于直观表示他的思想。
图1.3小于的设计
Peter让小李按照小于的设计重构Demo,小李看了看小于的设计图,很快完成。
相关代码如下:
Code:
IAttackStrategy接口
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLiAdv
7:
{
8:
internalinterfaceIAttackStrategy
9:
{
10:
voidAttackTarget(Monstermonster);
11:
}
12:
}
Code:
木剑
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLiAdv
7:
{
8:
internalsealedclassWoodSword:
IAttackStrategy
9:
{
10:
publicvoidAttackTarget(Monstermonster)
11:
{
12:
monster.Notify(20);
13:
}
14:
}
15:
}
Code:
铁剑
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLiAdv
7:
{
8:
internalsealedclassIronSword:
IAttackStrategy
9:
{
10:
publicvoidAttackTarget(Monstermonster)
11:
{
12:
monster.Notify(50);
13:
}
14:
}
15:
}
Code:
魔剑
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLiAdv
7:
{
8:
internalsealedclassMagicSword:
IAttackStrategy
9:
{
10:
privateRandom_random=newRandom();
11:
12:
publicvoidAttackTarget(Monstermonster)
13:
{
14:
Int32loss=(_random.NextDouble()<0.5)?
100:
200;
15:
if(200==loss)
16:
{
17:
Console.WriteLine("出现暴击!
!
!
");
18:
}
19:
monster.Notify(loss);
20:
}
21:
}
22:
}
Code:
怪物
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLiAdv
7:
{
8:
///
9:
///怪物
10:
///
11:
internalsealedclassMonster
12:
{
13:
///
14:
///怪物的名字
15:
///
16:
publicStringName{get;set;}
17:
18:
///
19:
///怪物的生命值
20:
///
21:
privateInt32HP{get;set;}
22:
23:
publicMonster(Stringname,Int32hp)
24:
{
25:
this.Name=name;
26:
this.HP=hp;
27:
}
28:
29:
///
30:
///怪物被攻击时,被调用的方法,用来处理被攻击后的状态更改
31:
///
32:
///
33:
publicvoidNotify(Int32loss)
34:
{
35:
if(this.HP<=0)
36:
{
37:
Console.WriteLine("此怪物已死");
38:
return;
39:
}
40:
41:
this.HP-=loss;
42:
if(this.HP<=0)
43:
{
44:
Console.WriteLine("怪物"+this.Name+"被打死");
45:
}
46:
else
47:
{
48:
Console.WriteLine("怪物"+this.Name+"损失"+loss+"HP");
49:
}
50:
}
51:
}
52:
}
Code:
角色
1:
usingSystem;
2:
usingSystem.Collections.Generic;
3:
usingSystem.Linq;
4:
usingSystem.Text;
5:
6:
namespaceIGameLiAdv
7:
{
8:
///
9:
///角色
10:
///
11:
internalsealedclassRole
12:
{
13:
///
14:
///表示角色目前所持武器
15:
///
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 小李打 妖怪