Java 类构造中的奇怪引用传递

Java 类构造中的奇怪引用传递,java,design-patterns,Java,Design Patterns,我是一名web开发人员(游戏开发是我的一项爱好),我已经见过自己多次使用以下范例。(无论是在开发服务器架构还是在视频游戏开发工作中)这看起来真的很难看,但我不知道如何解决。我将在游戏开发中给出一个例子,因为我最近注意到了它。这是我一直在做的RPG。每次战斗开始时,战斗引擎都会产生两个战斗方。每个战斗员都会设置一个与给定战斗员相关联的人工智能对象,该对象负责为未收到明确命令的玩家指挥移动: public class Combatant { ArtificialIntelligence a

我是一名web开发人员(游戏开发是我的一项爱好),我已经见过自己多次使用以下范例。(无论是在开发服务器架构还是在视频游戏开发工作中)这看起来真的很难看,但我不知道如何解决。我将在游戏开发中给出一个例子,因为我最近注意到了它。这是我一直在做的RPG。每次战斗开始时,战斗引擎都会产生两个战斗方。每个战斗员都会设置一个与给定战斗员相关联的人工智能对象,该对象负责为未收到明确命令的玩家指挥移动:

public class Combatant {

    ArtificialIntelligence ai = null;

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

        this.ai = new ArtificialIntelligence(this);
    }

}
以下是我不喜欢的:内部场(人工智能)在构建过程中需要战斗人员,因为它需要一些战斗人员场来指挥适当的行动。因此,为了方便起见,我保留了一个对战斗人员的引用,作为对人工智能对象的arg传入,但该对象包含对ai对象本身的引用!它创建了这种奇怪的递归,但我不知道如何处理它。AI对象需要很多特定于combatant的字段,这就是我传入整个对象的原因,但我不喜欢对象如何包含对AI字段的引用,AI字段包含在combatant字段中,combatant字段包含在Overlay AI类中。这是一种不好的做法,还是我只是想得太多了?

虽然这里没有“设计”问题-它只是您正在传递的一个引用-一个重要的考虑因素是,您应该在将
传递给另一个类之前初始化所有字段。否则,另一个类将在可能不一致的状态下访问此。这有时被称为从构造函数中“转义”

不要这样做

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"; 
    }

我肯定会避免循环依赖。单一责任原则也适用于救援。通过让人工智能对战斗人员进行操作,您可以消除在战斗人员中引用人工智能的需要。将所有依赖人工智能的战斗人员代码移到人工智能。战斗发动机将执行以下操作:

  • 创建一个与人工智能无关的独立战斗人员实例

  • 创建适当的人工智能实例,并将其传递给先前创建的战士

  • 或者,您可以创建一个名为CombatController的新类,该类由Combatant和ArtificialIntelligence传递。战斗发动机将执行以下操作:

  • 创建一个不依赖任何其他类的战斗员

  • 创建一个不依赖于任何其他类的人工智能

  • 创建一个战斗控制器,并将战斗人员和人工智能对象传递给它以供使用。战斗控制员应公开控制战斗人员的方法以及处理AI行为的方法

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


    很抱歉,我无法提供一个代码示例,因为我正在手机上键入此答案,格式化是一个难题

    您是否遇到堆栈溢出错误?我对此表示怀疑,如果不是,这里没有递归,只是引用传递。我想你在这里没什么问题。呜呜,我是个数学家,所以我的一些术语是缺乏的。你说得对,这只是引用传递。这是否仍然被视为一个非问题?在这个表单中嵌套引用不是很糟糕吗?回答你的问题,我没有任何错误。我只是觉得它看起来很糟糕,想听听大家的意见。一些关于循环依赖关系的引用:+1一些IDE会警告构造函数中有“泄漏此信息”的情况。很清楚,
    ArtificialIntelligence
    的构造函数(以及它调用的任何方法)将
    someField
    视为
    null
    。我认为保持这种循环依赖性不是一个好主意。看看我的答案!当这种依赖关系可以移动到两个类中的一个或一个全新的类时,这两个类就不需要部分地相互依赖。我也强烈反对这不是一个设计问题。正如bot的回答所解释的,这是一种循环依赖,这是一种设计风格。参见例如,这个答案:+1当然还有更多的选择;例如,您可以将人工智能需要的字段从Combatant提取到一个新类,比如CombatantState。战斗状态将是战斗状态中的一个领域,人工智能可以接受战斗状态。最好的解决方案取决于代码的需要。我完全同意。只有当你了解整个情况而不是问题的一部分时,使用什么方法才能清楚。无论哪种方式,循环依赖都可以很容易地避免!