这种递归是更一般的设计问题的症状。您当然可以尝试通过从构造函数中“泄漏”实例引用或将“构造”推迟到稍后调用的某些初始化方法(可能是懒惰的)来解决它,但我不推荐这个1。
为什么 GUI和Player 类必须是单例的,并且必须相互了解,更具体地说,必须在构建过程中相互了解?除了“更方便”之外,还有其他原因可以全局访问某个对象吗?并不是说方便不重要,但它通常不应该是设计决策的唯一原因。
更好的方法是完全摆脱单例,因为没有真正的理由不能同时存在 Player 和 GUI 的两个实例。当然,您的程序中可能只有一个,但这不是单例的目的。
此外,您应该仅在一个方向上具有依赖关系。试着想想什么可以没有对方而存在,什么不能。我认为 GUI 应该取决于 Player,因为您可能可以想象没有 GUI 的 Player,但是没有 Player 的 GUI 根本没有意义。因此,您首先构造一个 Player,然后构造一个 GUI,并将其操作的 Player 实例传递给它。如果您认为您需要从 Player 内部的任何地方访问您的 GUI 实例,您应该重新考虑您的设计并尝试使这些对象更加独立。这通常可以通过使用观察者模式来完成,并让 GUI 监听发生的变化/动作/事情。这样,您的应用程序代码根本不知道 GUI。但是,在您的 GUI 中,您可以随意传递 GUI 的实例。
关于引入“经理”对象或工厂模式的想法:它可能很有用,但你当然可以在没有它的情况下完成我上面所说的所有操作,并且仍然有一个理智的设计。我通常会反对“经理”课程,因为它们往往会做太多事情,并且通常是伪装的单身人士。然而,工厂可能很有用,但前提是您希望将事物的实际构造与它们的使用分离,例如允许稍后实现不同类型的 GUI。
所以一个简单的实现看起来像这样:
public static void main(...) {
Player player = new Player();
// maybe some other stuff to configure/set up the player
GUI gui = new GUI(player);
gui.show(); // or something similar
}
如果您想使用工厂,您当然可以将new ...
表达式替换为对您之前必须获得的工厂的调用。
1 为什么?好吧,例如,如果您成功构建了 GUI,但后来无法初始化它,例如抛出异常,会发生什么?您需要某种方式将此“无效”状态传达给已获得 GUI 实例的所有对象。此外,您必须确保在初始化 GUI 实例之前没有人使用它。