Java:如何干净地处理大量字段及其封装?

bad*_*adp 10 java getter encapsulation

假设我的任务是编写某种RPG代码.这意味着,例如,我想要跟踪其状态,如智力,伤害奖励或生命值.Character GameCharacter

我非常害怕在项目结束时我最终可能会处理非常多的字段 - 对于每一个我都必须确保他们遵循一组非常相似的约束和行为(例如,我希望它们在最小值和最大值之间受限制;我希望能够区分"基值"和"临时奖励";我希望能够增加和减少两者而无需通过设置者和吸气剂) .突然之间,对于每个领域,我都需要一个(两个?)吸气剂和四个安装者,也许还需要几个重置器!即使是10个字段,这意味着很多方法都很相似,eek.

对于DRYness,我已经开始封装了在Field类中弄乱那些统计数据的逻辑,这样我就可以编写代码如intelligence.applyBonus(10)hitpoints.get()(注意返回的值在范围内)等等.我甚至已经花了这么长的时间来创建类将这些字段组合在一起,但现在不是重点.

现在,我打了这个问题,而"堵" FieldGameCharacter:大多数Java教科书上说,每个类应该具有公共getter和setter私人领域.这在理论上听起来不错,而且我已经建立了一个整体课程int; 然而,当你发现自己打电话给吸气剂时,这个想法听起来并不那么坚固......一个吸气剂:

thisCharacter.getIntelligence().get() //eeek
Run Code Online (Sandbox Code Playgroud)

我宁愿直接进入这个领域.也许这是我的Python/VB [1]"背景",但对我来说它更清晰,更清晰,更直接:

thisCharacter.intelligence.get()
Run Code Online (Sandbox Code Playgroud)

公共领域的(理论)问题是我放弃对它的所有控制; 例如,在代码库中的某些其他点,由于不幸,可能会发生以下情况:

thisCharacter.intelligence = somethingThatReallyIsNull;
Run Code Online (Sandbox Code Playgroud)

听起来像一个微妙的错误...但是......我的意思是,我真的应该担心吗?我从来没有打算Field直接分配[2],我在Javadoc中记录了这不是应该做的事情,但我仍然是新来的,所以我有点撕裂.

所以我想听听你对这个主题的看法.封装的优势是如此巨大,以至于我应该继续使用吸气剂和吸气剂等等......或者我应该采取健康措施的封装并留下Field作为一个public领域?


[1]是的,我知道.我一直试图忘记.但我们最近也看到了一些C#和男人,不是属性甜.那好吧.

[2]除了在构造函数中!一个吸气剂不会让我摆脱错误的构造函数.

TMN*_*TMN 18

听起来像是在考虑你的想法if(player.dexterity > monster.dexterity) attacker = player.你需要更多地思考if(player.quickerThan(monster)) monster.suffersAttackFrom(player.getCurrentWeapon()).不要乱用裸露的统计数据,表达你的实际意图,然后围绕他们应该做的事情设计你的课程.无论如何,统计数据都是一个警察; 你真正关心的是一个玩家是否可以做某些动作,或者他们的能力/能力与一些参考.用"足够强大的玩家角色"(player.canOpen(trapDoor))而不是"角色是否具有至少50强度"来思考.

  • 好点子!超越D&D手册的简单转录. (2认同)

Uri*_*Uri 8

我的经验是,在需要大量字段的情况下,字段的数量,性质,命名和类型非常灵活,并且可能在项目的整个生命周期中发生变化,您可能需要某种地图而不是字段.

例如,具有从键到值的属性映射.

提供获取和设置属性的公共调用,但不要让每个人都使用它们(或确保它们不使用).相反,创建类来表示您感兴趣的每个属性,该类提供操作该属性的所有函数.例如,如果你有力量,你可以有一个"StrengthManipulation"类,它被初始化为一个特定的Player对象,然后提供getter,setter(所有有适当的验证和例外),也许还有像奖金计算力量等等. .

这样做的一个优点是,您可以将属性的使用与播放器类分开.因此,如果您现在添加一个Intelligence属性,则不必处理和重新编译仅操纵强度的所有内容.

至于直接访问字段,这是一个坏主意.当您访问VB中的字段(至少在旧VB中)时,通常会调用属性getter和setter,而VB只是为您隐藏了()调用.我的观点是你必须适应你正在使用的语言的约定.在C,C++,Java等中,您有字段并且有方法.调用方法应始终使用()来明确它是一个调用,并且可能发生其他事情(例如,你可能会遇到异常).无论哪种方式,Java的一个好处是它的语法和风格更加精确.

VB到Java或C++就像发短信到研究生科学写作.

顺便说一句:一些可用性研究表明,最好不要让构造函数有参数,而是在需要时构造和调用所有的setter.