我是一个网络开发者(游戏开发作为一种爱好),我看到自己多次使用以下范例。 (两者都在开发服务器架构和视频游戏开发工作。)它看起来真的很难看,但我不知道一个解决方案。我将在游戏开发中给出一个例子,因为它是我最近注意到它的地方。这是我一直在研究的角色扮演游戏。每次发动战斗时,CombatEngine都会创建两个战斗员派对。每个战斗者都设置一个与给定战斗者相关联的ArtificialIntelligence对象,该战斗员负责为没有接收明确命令的玩家指挥移动:
public class Combatant {
ArtificialIntelligence ai = null;
public Combatant()
{
// Set other fields here.
this.ai = new ArtificialIntelligence(this);
}
}
这就是我不喜欢的内容:内部场(ArtificialIntelligence)在施工期间使用一个作战者,因为它需要一些作战场以指示适当的行动。因此,为了方便起见,我保留了对作为一个arg传递给ArtificialIntelligence对象的战斗员的引用,但该对象包含对ai对象本身的引用!它创建了这种奇怪的递归,但我不知道如何解决它。 AI对象需要大量特定于战斗员的字段,所以这就是我传入整个对象的原因,但我不喜欢该对象如何包含对上覆战斗员中包含的ai字段的引用字段,包含在上覆的ai类中。这是不好的做法,还是我只是过度思考?
答案 0 :(得分: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";
}
答案 1 :(得分:5)
我肯定会避免循环依赖。来救援的单一责任原则。您可以通过让ArtificialIntelligence在Combatant上运行来消除对Combatant中的Artificialntelligence的引用的需要。将所有依赖于ArtificialIntelligence的Combatant代码移到ArtificialIntelligence上。 CombatEngine将执行以下操作:
创建与Artificialntelligence无关的独立战斗员实例。
创建适当的Artificalintelligence实例并将其传递给之前创建的争斗者。
或者,您可以创建一个名为CombatController的新类,该类传递一个Combatant和一个ArtificialIntelligence。 CombatEngine将执行以下操作:
创建一个不依赖于任何其他类的战斗员
创建一个不依赖于任何其他类的人工智能
创建一个CombatController并将其传递给Combatant和ArtificialIntelligence对象以供使用。 CombatController应该公开控制Combatant的方法以及处理AI行为。
无论您使用上述哪种方法,都可以消除困扰您的循环依赖性。
我很抱歉我无法提供代码示例,因为我正在通过手机输入此答案并且格式化很麻烦。