在班级建设中传递奇怪的参考

Sal*_*Sal 9 java design-patterns

我是一个网络开发者(游戏开发作为一种爱好),我看到自己多次使用以下范例.(两者都在开发服务器架构和视频游戏开发工作.)它看起来真的很难看,但我不知道一个解决方案.我将在游戏开发中给出一个例子,因为它是我最近注意到它的地方.这是我一直在研究的角色扮演游戏.每次发动战斗时,CombatEngine都会创建两个战斗员派对.每个战斗者都设置一个与给定战斗者相关联的ArtificialIntelligence对象,该战斗员负责为没有接收到明确命令的玩家指挥移动:

public class Combatant {

    ArtificialIntelligence ai = null;

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

        this.ai = new ArtificialIntelligence(this);
    }

}
Run Code Online (Sandbox Code Playgroud)

这就是我不喜欢的内容:内部场(ArtificialIntelligence)在施工期间使用一个作战者,因为它需要一些作战场以指示适当的动作.因此,为了方便起见,我保留了对作为一个arg传递给ArtificialIntelligence对象的战斗员的引用,但该对象包含对ai对象本身的引用!它创建了这种奇怪的递归,但我不知道如何解决它.AI对象需要大量特定于战斗员的字段,所以这就是我传入整个对象的原因,但我不喜欢该对象如何包含对上覆战斗员中包含的ai字段的引用字段,包含在上覆的ai类中.这是不好的做法,还是我只是在思考它?

Boh*_*ian 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"; 
    }
Run Code Online (Sandbox Code Playgroud)

  • 我也非常不同意这不是一个设计问题.正如bot的回答所解释的那样,这是一种循环依赖,这是一种设计气味恕我直言.参见例如这个答案:[从编码风格的角度来看圆形类依赖性是不是很糟糕?](http://stackoverflow.com/questions/1356304/are-circular-class-dependencies-bad-from-a-coding-style -观点看法) (3认同)
  • 我不认为保持这种循环依赖是个好主意.看到我的回答!当此依赖关系可以移动到两个类之一或全新类时,不需要两个类部分地相互依赖. (2认同)

CKi*_*ing 5

我肯定会避免循环依赖.来救援的单一责任原则.您可以通过让ArtificialIntelligence在Combatant上运行来消除对Combatant中的Artificialntelligence的引用的需要.将所有依赖于ArtificialIntelligence的Combatant代码移到ArtificialIntelligence上.CombatEngine将执行以下操作:

  1. 创建与Artificialntelligence无关的Independent Combatant实例.

  2. 创建适当的Artificalintelligence实例并将其传递给先前创建的Combatant.

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

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

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

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

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

对不起,我无法提供代码示例,因为我从手机输入这个答案,格式化很痛苦.