使用两个单身人士时如何避免递归?

时间:2013-03-14 15:16:09

标签: java design-patterns recursion singleton infinite

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

我也有Player Class(有点像Audioplayer),也是Singleton。

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

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

由于

4 个答案:

答案 0 :(得分:2)

我可能会avoid the singleton pattern altogether。正如您所发现的那样,它使控制创建生命周期变得困难。

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

答案 1 :(得分: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
    }
}

答案 2 :(得分:0)

我会使用静态初始化块。在构造类时调用它。而不是在创建对象时。它只召唤一次。 see more

答案 3 :(得分:0)

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

为什么GUI Player类必须是单身人士并且必须彼此了解,更具体地说,在构建期间必须彼此了解?除了'更方便'之外还有一个理由可以全局访问某个对象吗?并非方便并不重要,但通常不应该是设计决策的唯一原因。

更好的方法是完全摆脱单身人士,因为没有真正的理由不能同时存在两个播放器和GUI实例。当然,你的程序可能只有一个,但这不是Singletons的目的。

此外,您应该只在一个方向上具有依赖性。试着想想没有对方可以存在什么,什么不能存在。我认为GUI应该依赖于播放器,因为你可能会想象有一个没有GUI的播放器,但没有播放器的GUI根本就没有意义。因此,您首先构造一个Player,然后构造一个GUI并将其传递给它所运行的Player实例。如果您认为需要从Player内的任何位置访问GUI实例,您应该重新考虑设计并尝试使这些对象更加独立。这通常可以通过使用Observer模式完成,并让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实例。