9

我是一名网络开发人员(游戏开发作为一种爱好),我已经看到自己多次使用以下范例。(无论是在开发服务器架构还是在视频游戏开发工作中。)它看起来真的很丑,但我不知道有什么解决方法。我将在游戏开发中举一个例子,因为这是我最近注意到的地方。这是我一直在制作的RPG。每次发起战斗时,CombatEngine 都会创建两个战斗方。每个 Combatant 都会设置一个与给定 Combatant 相关联的人工智能对象,该对象负责为未收到明确命令的玩家指示动作:

public class Combatant {

    ArtificialIntelligence ai = null;

    public Combatant()
    {
        // Set other fields here.

        this.ai = new ArtificialIntelligence(this);
    }

}

这是我不喜欢的:内部字段(ArtificialIntelligence)在构建过程中需要一个 Combatant,因为它需要一些 Combatant 字段来指示适当的操作。因此,为方便起见,我保留了对作为 arg 传递给ArtificialIntelligence 对象的战斗员的引用,但该对象包含对ai 对象本身的引用!它创建了这种奇怪的递归,但我不知道如何解决它。AI 对象需要大量特定于战斗人员的字段,这就是为什么我传入整个对象的原因,但我不喜欢对象如何包含对包含在上层战斗人员中的 ai 字段的引用字段,包含在上层 ai 类中。这是不好的做法,还是我只是想多了?

4

2 回答 2

9

虽然这里没有“设计”问题——它只是你传递的一个参考——一个重要的考虑因素是你应该在传递给另一个类之前初始化你的所有字段。this否则,其他类将可以访问this可能不一致的状态。这有时被称为让this构造函数“逃脱”。

不要这样做...

public class BadCombatant {

    ArtificialIntelligence ai = null;
    String someField;

    public BadCombatant() {
        this.ai = new ArtificialIntelligence(this);
        // Don't do this - ArtificialIntelligence constructor saw someField as null
        someField = "something"; 
    }
于 2012-09-19T03:18:15.187 回答
5

我肯定会避免循环依赖。在救援中引入了单一责任原则。您可以通过让人工智能在战斗员上运行,从而消除在战斗员中引用人工智能的需要。将依赖于人工智能的 Combatant 中的所有代码移至人工智能。CombatEngine 将执行以下操作:

  1. 创建一个与人工智能无关的独立战斗实例。

  2. 创建适当的 Artificalintelligence 实例并将之前创建的 Combatant 传递给它。

或者,您可以创建一个名为 CombatController 的新类,该类传递一个 Combatant 和一个人工智能。CombatEngine 将执行以下操作:

  1. 创建一个不依赖于任何其他类的 Combatant

  2. 创建不依赖于任何其他类的人工智能

  3. 创建一个 CombatController 并将 Combatant 和 ArtificialIntelligence 对象传递给它以使用。CombatController 应该公开控制 Combatant 以及处理 AI 行为的方法。

无论您使用上述哪种方法,您都可以消除困扰您的循环依赖。

很抱歉,我无法提供代码示例,因为我正在用手机输入此答案并且格式化很痛苦。

于 2012-09-19T07:31:20.300 回答