比方说,我有编码某种角色扮演游戏的任务。这意味着,例如,我将要跟踪的 Character GameCharacter和它们的统计信息,如智力,损害奖金或生命点数。

我肯定害怕,在项目结束时,我最终可能会具有非常高的数字领域的处理 - 并为每个我必须确保他们遵循一个非常相似的一套约束和行为(对例如,我想他们一个最小和一个最大间界;我希望能够“基值”和“临时奖金”之间进行区分;我希望能够增加和减少两个,而无需通过制定者去和getter)。突然间,每个字段我需要一(二?)的getter和四个制定者,也许一对夫妇复位器呢!即使对于10个视野,这意味着方法很多都是一样,伊克。

有关干我已开始包封在Field类那些统计搞乱的逻辑,这样我可以编写代码,如intelligence.applyBonus(10)hitpoints.get()(其负责返回的值在范围内)等我甚至去这样的长度来创建类基团的那些字段一起,但现在这不是点。

现在,我打了这个问题,而“堵” FieldGameCharacter:大多数Java教科书上说,每个类应该具有公共getter和setter私人领域。这在理论上听起来不错,我已经建立围绕int一整类;然而,当你发现自己调用一个getter得到......一个getter想法听起来并不为实:

thisCharacter.getIntelligence().get() //eeek

我宁愿直接访问字段。也许这是我的Python / VB [1]“背景”,但对我来说是更清洁,更清晰,更直观:

thisCharacter.intelligence.get()

在(理论值)问题公共字段是我要放弃它所有的控制;例如在代码库一些其它点,由不幸,下面可能会发生:

thisCharacter.intelligence = somethingThatReallyIsNull;

听起来像是一个细微的错误......可是......我的意思是,我真的应该担心?一,我从来没有计划分配的Field直接[2],我在Javadoc已经证明,这是不是一件应该做的事,但还是我在这里新的,所以我有点撕裂。

所以我想听听你对这个话题。是封装的优势,使大规模的,我应该继续和有吸气getter和setter方法getter和等等......或者我应该采取封装健康措施,并离开Field作为public场?


[1]是的,我知道。我一直试图忘记。但是,我们刚刚也看到了一点C#和人,是不甜的属性。哦。

[2]除了在构造!和一个getter不会从一个错误的构造救我。

有帮助吗?

解决方案

我的经验是,在情况下,您需要的很多的领域,数量,性质,命名和类型的字段非常灵活和有可能在整个项目的生命周期来改变你很可能需要某种形式的地图,而不是字段。

例如有从键值的属性映射。

提供用于获取和设置属性市民来电,但不要让大家使用它们(或确保他们不这样做)。相反,创建类来表示每个属性你有兴趣,并且该类提供的所有功能,操纵该属性。举例来说,如果你有实力,你可以有被初始化为一个特定的播放器对象“StrengthManipulation”类,然后提供的getter,setter方法(所有适当的验证和例外),也许事情就像奖金计算强度等

这样做的好处是,你脱钩您的播放器类使用你的属性。所以,如果你现在添加智能属性,你不必处理,并重新编译操纵唯一的长处一切。

作为用于直接访问的字段,这是一个好主意。当你在VB访问一个字段(至少在老VBS),通常所说的属性getter和setter和VB只是隐藏的()调用你。我的观点是,你必须去适应你所使用的语言的约定。在C,C ++,Java语言和像你这样的字段,你有方法。调用一个方法应该总是有()要清楚,这是一个电话,其他的事情可能发生(例如,你可以得到一个例外)。无论哪种方式,对Java的好处之一是它的更精确的语法和风格。

VB到Java或C ++是像发短信研究生院科学写入。

BTW:一些可用性研究表明,最好是没有参数的构造函数和而构建,如果你需要他们呼吁所有的setter方法。

其他提示

听起来你在if(player.dexterity > monster.dexterity) attacker = player的角度来思考。你需要考虑更喜欢if(player.quickerThan(monster)) monster.suffersAttackFrom(player.getCurrentWeapon())。各地不要惹裸统计,表达你的意图实际再设计围绕他们应该怎么做你的类。统计是一种逃避无妨;你真正关心的是球员是否可以或不可以做一些动作,或自己的能力/容量与一些参考。可以考虑这样的“是玩家角色足够强”代替(player.canOpen(trapDoor))“确实的字符具有至少50强度”。

史蒂夫·耶格有一个非常有趣的(如果长时间)的博客文章涵盖了这些问题:的通用设计模式

要我来说,它看起来像“thisCharacter”很可能有一个“智能”对象来处理幕后的情报,但我怀疑这是否应该是公开的。你应该只暴露thisCharacter.applyInt和thisCharacter.getInt,而不是与它交易的对象。不要暴露你实现这样的。

请您的私人领域!你永远不希望暴露太多的API的。你总是可以使一些是私人的公众,而不是倒过来,在未来的版本。

想想,如果你会做出进入下一个MMORPG。你有缺陷,错误,以及不必要的恶了很多范围。确保不可变属性是最终

想想一个DVD播放机,以其miniamilistic接口(播放,停止,菜单),然而这样的技术性内。你要隐瞒一切都在你的程序的非重要的。

这听起来像你的主要抱怨是没有这么多的二传手/ getter方法的抽象,但使用它们的语言语法。也就是说,你喜欢的东西,如C#样式属性。

如果是这种情况,那么Java语言具有相对小向你提供。直接的现场访问是罚款,直到你需要切换到一个getter或setter,然后你将有一些重构做的(可能是好的,如果你控制了整个代码库)。

当然,如果Java平台是一个要求,但语言不是那么有其他选择。 Scala有一个非常漂亮的属性的语法,例如,与许多其他功能,可以对这样的项目是有用的一起。最重要的是,它在JVM上运行,所以你仍然可以得到你想要在Java语言写就获得相同的便携性。 :)

什么你看上去有这里是复合模型的单个层。

您可能想补充一点,抽象添加到模型中,而不是仅仅有作为一组的低级别车型的方法。

中的字段应该是最后的,所以即使你没有让他们公开,你可以不小心被分配null给他们。

“获取”前缀是用于所有干将,所以它可能更最初看上去比一个新的问题,因为这样的。

  

是封装的优势,使大规模的,我应该继续和有吸气getter和setter方法getter和等等......或者我应该采取封装在健康的措施,将该字段作为公共领域?

IMO,封装无关与缠绕的私人领域的getter / setter。在小剂量,或写入通用库的情况下,折衷是可以接受的。但是,当在像您所描述的一个系统,它是一个一个的反模式

与getter / setter方法的问题是,它们创建的那些方法的对象和系统的其余部分之间过于紧密耦合。

一的实际封装的一个优点是,它降低了getter和setter的需要,从系统中的过程的其余部分去耦的对象。

而不是setIntelligence暴露GameCharacter的实施,为什么不给GameCharacter,更好地反映它在游戏系统中的作用的接口?

例如,代替:

// pseudo-encapsulation anti-pattern
public class GameCharacter
{
  private Intelligence intelligence;

  public Intelligence getIntelligence()
  {
    return intelligence
  }

  public void setIntelligence(Intelligence intelligence)
  {
    this.intelligence = intelligence;
  }
}

为什么不试试这个:

// better encapsulation
public class GameCharacter
{
  public void grabObject(GameObject object)
  {
    // TODO update intelligence, etc.
  }

  public int getIntelligence()
  {
    // TODO
  }
}

,甚至更好:

// still better
public interface GameCharacter
{
  public void grabObject(GameObject object); // might update intelligence
  public int getIntelligence();
}

public class Ogre implements GameCharacter
{
  // TODO: never increases intelligence after grabbing objects
}

在其它字,一个GameCharacter可以抓住GameObjects。每个GameCharacter的敛同一游戏物体的影响可以(也应该)而变化,但细节完全每个GameCharacter实现中包封。

注意GameCharacter现在如何是负责处理其自己的情报更新(范围检查,等等),其可发生,因为它抓住GameObjects,例如。 setter方法(和你注意并发症有它)已经消失。您可能能够完全与getIntelligence方法来分配,视情况而定。艾伦·霍尔布采取这一想法的合乎逻辑的结论,但但这种做法似乎并不是很常见的。

在除乌里的答案(我完全支持),我想建议你考虑定义数据属性映射。这将使你的程序非常灵活,会分解出大量的代码,你甚至不知道你不需要。

例如,属性就可以知道其绑定到屏幕上的哪一个领域,哪一个领域它绑定到数据库中,一个动作列表时执行的属性改变(一个重新计算击中%可能适用于强度和DEX ...)

这样做,这样,就具有每属性NO代码写一个类出到DB或在屏幕上显示它。你只是遍历的属性,并使用内部存储的信息。

同样的事情可以适用于技能 - 事实上,属性和技能,可能会从同一个基类派生

你走这条路之后,你可能会发现自己有一个相当严重的文本文件来定义的属性和技能,但加入一项新技术将是那么容易,因为:

Skill: Weaving
  DBName: BasketWeavingSkill
  DisplayLocation: 102, 20  #using coordinates probably isn't the best idea.
  Requires: Int=8
  Requires: Dex=12
  MaxLevel=50

在某些时刻,添加这样的技术人员将任何不需要的代码的变化,它可以全部在数据做得相当容易,并且所有的数据被存储在附加到类技能单一对象。你可以,当然,定义操作以同样的方式:

Action: Weave Basket
  text: You attempt to weave a basket from straw
  materials: Straw
  case Weaving < 1
    test: You don't have the skill!
  case Weaving < 10
    text: You make a lame basket
    subtract 10 straw
    create basket value 8
    improve skill weaving 1%
  case Weaving < 40
    text: You make a decent basket
    subtract 10 straw
    create basket value 30
    improve skill weaving 0.1%
  case Weaving < 50
    text: You make an awesome basket!
    subtract 10 straw
    create basket value 100
    improve skill weaving 0.01%
  case Weaving = 50
    text: OMG, you made the basket of the gods!
    subtract 10 straw
    create basket value 1000

虽然这个例子是非常先进的,你应该能够想象它将如何与绝对没有代码来完成。想象一下,这将是多么困难的事这样的事情没有代码,如果你的“属性/技能”实际上是成员变量。

考虑使用“建模”的框架,如Eclipse的EMF。 这包括定义使用类似Eclipse的EMF编辑器中的对象, 或纯XML,或在Rational Rose中。它并不像听起来那么困难。 您可以定义属性,约束等,然后将生成框架 为你的代码。它增加了@generated标签,它增加了如零部件 getter和setter方法。您可以自定义代码,后来编辑 它通过手动或经由一些GUI,并重新生成Java文件。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top