1

我有一个 Gui 类,它是一个 Singleton,因为许多其他类必须使用 Gui 的方法,并且任何时候都应该只有一个 Gui 的实例。

我也有播放器类(有点像音频播放器),它也是一个单例。

当我启动 Gui 时,我告诉玩家获取当前状态(这会创建玩家的新实例)并将其显示在 Gui 上。因此,玩家创建了一个 Gui 的新实例,因为 Gui 的 Constructor 还没有完成。

因此,这会产生无休止的递归。我想保留单例模式。有没有办法将 getInstance() 中的实例设置为“null”以外的其他值,即使 Constructur 尚未完成?

谢谢

4

4 回答 4

2

我也许会完全避免单例模式。正如您所发现的,它使控制创建生命周期变得困难。

相反,我会创建一个GuiManager,它创建Gui然后将其注入到需要了解它的适当组件中?这称为控制反转(或依赖注入)并避免了对全局状态的需要。好处包括使测试变得容易(因为周围的框架控制着对象的生命周期)并且这些对象的创建是可预测的。

于 2013-03-14T15:19:57.807 回答
0

创建初始化函数

public class Gui
{
    public static Gui instance;
    public static Gui getInstance()
    {
        if(instance == null)
        {    
            instance = new Gui();
            instance.initialize();
        }
        return instance;        
    }

    private Gui()
    {

    }

    private initialize()
    {
        // do constructor work here
    }
}
于 2013-03-14T15:22:14.077 回答
0

我会使用静态初始化块。在构造类时调用它。不是在创建对象时。并且它只调用一次。看更多

于 2013-03-14T15:22:26.923 回答
0

这种递归是更一般的设计问题的症状。您当然可以尝试通过从构造函数中“泄漏”实例引用或将“构造”推迟到稍后调用的某些初始化方法(可能是懒惰的)来解决它,但我不推荐这个1

为什么 GUIPlayer 类必须是单例的,并且必须相互了解,更具体地说,必须在构建过程中相互了解?除了“更方便”之外,还有其他原因可以全局访问某个对象吗?并不是说方便不重要,但它通常不应该是设计决策的唯一原因。

更好的方法是完全摆脱单例,因为没有真正的理由不能同时存在 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 实例之前没有人使用它。

于 2013-03-14T15:25:43.153 回答