Python、循环依赖与单例模式

1 投票
1 回答
1275 浏览
提问于 2025-04-17 17:57

我现在陷入了一个麻烦的境地。

我正在用Python和Kivy开发一个应用,使用的是PyDev这个工具。

这个应用需要运行在大约10个系统上,所以我把它们放进一个引擎里来处理所有的事情。

为了方便访问,我通过(最糟糕的)单例模式来获取这个引擎。

main.py

#main.py
from code import engine

class MyApp(App):
    def build(self):
        engine.GetInstance().Initialize()

if __name__ == '__main__':
    MyApp().run()

engine.py

#engine.py
from code import system1
from code import system2

gEngineInstance = None
def GetInstance():
    global gEngineInstance
    if (gEngineInstance == None):
        gEngineInstance = Engine()
    return gEngineInstance

class Engine():
    mSystem1 = None
    mSystem2 = None

    def Initialize(self):
        self.mSystem1 = system1.System1()
        self.mSystem2 = system2.System2()
    # Omitted

不幸的是,这导致了一些麻烦的循环依赖。

主程序需要创建引擎,并且要知道引擎的存在,这样引擎才能导入其他模块,而这些模块又需要导入引擎。

问题是:系统模块又要导入引擎,这就形成了循环引用。

system1.py

#system1.py
from code import engine

class System1():
    def SomeMethod(self):
        engine.GetInstance().mSystem2.DoThings()

你能理解我的意思。

为了暂时解决这个问题,我在代码里到处写了一些丑陋的代码:

system1.py

#system1.py

class System1():
    def SomeMethod(self):
        from code import engine
        engine.GetInstance().mSystem2.DoThings()

这样做可以在那行代码之前阻止导入,这样虽然可以,但看起来不太对劲,感觉我在做错事。

我很想把引擎作为一个引用传递给每个系统的构造函数,但这需要一些重构。我想知道有没有更好的方法来解决这种单例和循环引用的问题,以便将来能避免。

1 个回答

2

我们可以想象有一个“注册”机制,每个 system 模块都可以用一些模块级别的代码来“注册”自己给 Engine 类:

engine.py

class Engine():
    @classmethod
    def register(cls, type):
        ...

system1.py

from engine import Engine

class System1():
    ...

Engine.register(System1)

这样一来,Engine 就不需要直接知道它里面接入了什么东西。

撰写回答