Java 面向对象设计
Posted
技术标签:
【中文标题】Java 面向对象设计【英文标题】:Java Object-Oriented Design 【发布时间】:2016-01-19 02:57:51 【问题描述】:我对我的第一个 java 项目(以 OO 为重点)有了一个想法。这个项目是某种非常基础的角色扮演游戏(没有 GUI,它非常基础),所以我有一些 OOD 问题。
玩家(没有玩家职业,至少现在是这样)可以选择一个角色职业(你知道,战士、巫师等……将来他可能可以选择几个角色,这样他就可以拥有一个派对)。创建角色后,他可以与其他敌人作战(由程序控制)。
每个角色都有一些信息,例如:角色等级(如战士)、等级、护甲等级、能力(力量、敏捷、智慧等)。 每个类都有一个库存。每个字符都有一些方法,例如:
攻击(使用武器,如果他是施法者,那么施法也可以 使用攻击)。
防御(如防御法术或使用招架等技能。注意:更改 盔甲类。某些角色职业(如巫师)可以施法。大多数法术将是攻击性或防御性的,因此它们可以使用攻击或防御方法。 例如,假设 castFireball 可以调用 Attack(20)。一些咒语 可以做其他事情,比如 castHeal 可以治愈角色并改变 当前生命值。
购买(未来可选)。当然,所有角色的实现都相同。
从库存中添加/移除。建议的实现: 我考虑过创建一个抽象类(包含等级、装甲类、能力(如力量、敏捷、智慧等)等信息。以及一些方法,如攻击和防御。其他特定类将扩展 Character,因此它看起来像:
Character (abstract)
Character Class (like fighter)
Level
Hit Points
Current Hit Points
Armor Class
.
.
.
Inventory (List)
Strength
Dexterity
Wisdom
Fighter Wizard Rouge Cleric (All extends Character)
问题:
-
在这种情况下使用抽象类被认为是一个好的设计?您会建议使用界面并更改设计吗?
我应该为力量、智慧等能力创建另一个课程,还是可以将其作为角色的一部分?
我应该为库存创建另一个类吗?我认为它可能会更好,对吧?
使用枚举存储所有武器、盔甲和盾牌(未来可能还有其他东西)的数据是一个很好的解决方案吗?
Spells - 我不确定什么是实现它们的好方法。我可以创造
一个法术类,每个法术都有静态方法(如 castFireball、castHeal 方法)。施法当然只与施法者角色相关(每个角色都有一个已知的法术列表,所以他只能施展他知道的法术)。这是实现它的好方法吗?
我也可以使用txt文件,从文件中获取相关数据,但我不喜欢这个想法。
请记住,它应该是基本的,但应该为将来的更改和添加进行计划。它看起来像:
你想怎么攻击?
-
匕首(主要武器)
剑
施法
3
你想施什么咒语?
-
火球
治愈
冰风暴
1
你用火球击中敌人,造成 20 点伤害。
这很模糊,但你明白了..
非常感谢!!
【问题讨论】:
【参考方案1】:我建议不要将Character
设为(例如)Fighter
的抽象基类。作为一名战士只是角色的一个属性。例如,我只是告诉你他可以挥舞剑和穿板甲。在某些游戏中,假设Warrior
角色始终是战士。然后,当需求改变时,角色可以改变职业,比如法师,就会出现整个数据迁移问题,而不仅仅是属性的改变。克
尽可能保持继承树的浅层。尽可能使用聚合和组合而不是继承。
【讨论】:
我认为是这样。事实上,我会更进一步,问为什么一个角色只能属于一个阶级。在某些游戏中,只有技能,在这样的游戏中,我可以想象检查this.skills.armorwearingskill >= armor.skillrequredToWear
或类似的东西。我认为这为需求变化提供了更大的灵活性。而且它仍然可以通过与其他属性的一组约束相关联的字符类来适应管理您提到的这些方面的字符类。处理不断变化的需求的能力是这里的价值。如果它们不改变,继承就可以了。
我明白你的意思了。你是对的,一个字符类只是一个属性。如果一个字符可以是多个类,那么使用聚合和组合是比继承更好的设计。如果一个字符只能是一个字符类,那么我的抽象类可以正常工作。感谢您的提示:)
@Niminim 问问你自己......一个角色是一个职业还是一个角色有一个职业?在你第一次看到继承的地方看到组合通常会导致更好的设计。
我只是想到了一些事情——假设我不使用 Character 作为抽象类,那么施法者呢。所有角色都可以使用武器攻击、购买东西和做其他事情,但只有施法者可以施法,所以他们有独特的信息,如每天的法术、已知的法术总数等,以及另一种独特的方法 - castSpells。创建一个作为 character 子类的 SpellCaster 类是个好主意吗?
什么可以阻止战士进行施法训练?如果你沉迷于字符类,那么一定要创建Character
的子类,但要了解你对未来方向的限制。【参考方案2】:
一般来说,B
类应该是 A
的子类,前提是它们之间存在 is-a 关系——也就是说,如果说任何B
也是A
的一个实例。通过应用这个,你可以例如看到字符类是 Character
的子类的唯一可行候选者:A Warrior
是 Character
,但不是Weapon
/em> 一个Character
。相反,其他类和Character
之间存在 has-a 关系:a Character
has 和 Weapon
。在这种情况下,您应该使用 composition:Character
类可以有一个 Weapon
类型的字段(或者,更有可能是一个 List<Weapon>
类型的字段,这样您就可以拥有多种武器)。
但即使您可以创建一个类层次结构,也不确定您是否应该。如果角色类之间的差异可以完全实现为统计差异(可能只是类中的字段)或一些简单的能力差异,您可能只需要Character
类。另一方面,如果 行为 差异很大,并且您最终会得到一堆 if
语句来为不同情况下的各种字符类选择适当的行为,那么明智的做法是引入子类。但是,作为@plalx 和@B。 Dalton 指出,通常可以改用组合,将行为差异提取到抽象的CharacterAbilities
类及其子类中。
【讨论】:
当然,起初看起来战士是一个角色,但这完全是一个视角问题。一个角色是一个阶级还是一个角色有一个阶级?您通常可以扭转局面,最终以构图结束,这会导致设计更加灵活。 @plalx:够公平的;看我的新段落。 感谢您的建议,阿斯蒙德!【参考方案3】:在这里使用抽象类效果很好,因为所有其他字符类都将从该类扩展,并且该类本身永远不会被实例化。
1234563一个用于当前能力值,另一个用于没有增益/减益的基础值。将库存作为一个类是一个好主意。有些人可能会想创建一系列库存物品并根据游戏需要对其进行操作。我认为创建一个单独的类可以很好地封装所有内容,即使您只是在操作一个数组。
枚举在创建武器时很有用,但我也建议为此创建一个单独的类。如果您对所有项目使用枚举,您最终可能不得不使用大量数学运算,特别是除法和模块化来获取项目类型。创建一个项目类并将其扩展为不同的项目类型允许所有项目使用父类类型包含在一个公共数组中,同时赋予它们不同的统计/能力/用途。
法术可以遵循类似于我上面描述的物品的方式(事实上,如果你想将法术放在你的库存中,它可以是一个物品)。确保有一些枚举来描述法术及其功能,然后在施法时提供解释这些的方法。
【讨论】:
1+2+3。谢谢! 4. 我考虑过分别为武器、盾牌、盔甲和“其他东西”创建枚举,尽管创建另一个类听起来也不错 5.如果我做对了,那么您建议枚举将包含信息和方法,而另一个方法将调用该方法,对吗? 如果您将所有项目保留为不带类的枚举,则无论何时要打印它们的名称、损坏或防御,都需要通过翻译器运行它们。这最终会成为一个很长的 switch 语句,但绝对是解决它的一种方法。我认为将这些信息存储在一个类中会更容易。对于 5,我的意思是所有法术都应该有一个在施法时调用的通用方法,枚举告诉这个方法会发生什么。这样一个物体就可以施展法术而无需真正关心它是什么法术,而让法术完成其余的工作。【参考方案4】:类应该有一个单一的责任(或者更具体地说,一个改变的单一原因)
1) 抽象类看起来不错,因为您可以在类中包含通用行为,从而减少重复。一个接口只定义了“合约”
2) 见开场白,听起来像是另一种责任。
3) 见 2
4) 取决于内容,课程可能会更好
5) 可能是一个不同的抽象类从字符继承来确定法术属性。避免使用静态方法。还值得一看咒语的设计模式。可以有一个带有“castSpell”方法的接口,并且每个法术都实现了自己的功能。
有很多不同的选择 - 最好去看看有什么用。如果遇到困难,请发布代码。
【讨论】:
【参考方案5】:至于武器、盾牌和法术,我将它们建模成两个界面:
PassiveItem - 无需执行任何操作即可修改角色能力的东西(例如,盾牌可以增加他们的防御力) 这会有某种applyEffect()
方法来修改能力(可能创建一个基础能力的副本,然后在这些上运行所有被动物品的applyEffect()
以获得物品的最终能力)
ActiveItem - 需要角色动作才能产生效果的武器、物品和法术
这将有方法performAction(Character self, Character target)
以某种方式修改拖曳战斗字符,例如HealSpell
实现会增加角色的生命值,Dagger
会攻击目标。
【讨论】:
以上是关于Java 面向对象设计的主要内容,如果未能解决你的问题,请参考以下文章