任何人都可以用一个简单的蟒蛇来解释“好莱坞原则”/控制反转

时间:2011-06-17 17:08:47

标签: python inversion-of-control twisted

我对Twisted web框架非常感兴趣。据我所知的框架 使用好莱坞原则。我只知道这个词,但完全没有 关于这种设计模式的想法。 我已经做了很多谷歌搜索的实施 Python中的好莱坞原则。但结果很少。 有没有人能给我看一些简单的python代码来描述这种设计模式?

3 个答案:

答案 0 :(得分:6)

我以前从未听过“好莱坞原则”这个词,也不熟悉Twisted(虽然我觉得我应该这样)。但控制反转的概念并不那么困难。我认为GUI编程是介绍它的好方法。请考虑here中的以下内容(稍加修改)。

import Tkinter

class App(object):
    def __init__(self, master):
        frame = Tkinter.Frame(master)
        frame.pack()

        self.button = Tkinter.Button(frame, text="QUIT", fg="red", command=frame.quit)
        self.button.pack(side=Tkinter.LEFT)

        self.hi_there = Tkinter.Button(frame, text="Hello", command=self.say_hi)
        self.hi_there.pack(side=Tkinter.LEFT)

    def say_hi(self):
        print "hi there, everyone!"

root = Tkinter.Tk()
app = App(root)

root.mainloop()

这是控制反转的一个非常简单的例子。它使用回调 - 因此Hollywood principle名字对象(感谢Sven的链接)。这个想法是你写了一个函数,但你从来没有调用它。相反,你把它交给另一个程序并告诉该程序何时调用它。然后你控制该程序。以下是代码的详细说明:

import Tkinter

class App(object):

我们从一个类定义开始,它将保存我们的回调并将它们传递给我称之为“主程序”的相应部分。

    def __init__(self, master):

我们班需要一个“硕士课程”;主程序将调用我们定义的函数。在这种情况下,它是GUI的根窗口。更准确地说,在GUI编程的上下文中,我们可能会说masterframe

        frame = Tkinter.Frame(master)
        frame.pack()

这两行创建了一个Frame对象,它本质上是一个包含小部件的框。你会在一秒钟内看到一个小部件。正如您所看到的,它还有一个父级 - 与我们App的父级相同:master

        self.button = Tkinter.Button(frame, text="QUIT", command=frame.quit)
        self.button.pack(side=Tkinter.LEFT)

self.button是一个小部件。使用Tkinter.Button创建它时,会为其提供一些属性,例如标签(text="QUIT")。你还告诉它它的父亲是什么 - 在这种情况下,不是master,而是frame。所以现在我们有了一个层次结构 - master -> frame -> button。但我们最重要的是:command=frame.quit。这告诉按钮通过鼠标单击激活时该怎么做。简而言之,这就是回调。在这里,我们传递frame的{​​{1}}方法,在这种情况下导致整个程序退出。请注意,该功能后面没有quit - 这是因为想要调用它。我们只想将其交给()

button

这是另一个与第一个小部件几乎相同的小部件,唯一的例外是我们已经通过 self.hi_there = Tkinter.Button(frame, text="Hello", command=self.say_hi) self.hi_there.pack(side=Tkinter.LEFT) 而不是将self.quit作为回调传递。由于这是在下面定义的,您可以替换您想要的任何功能。 (在上述两个行中,self.say_hi只是告诉self.button.pack它应该在Button中的位置。)

frame

def say_hi(self): print "hi there, everyone!" 用于定义say_hi按钮的功能。

Hello

现在我们调用我们的类,创建一个实例。我们创建根窗口,然后创建一个root = Tkinter.Tk() app = App(root) 实例,其中App为其父级。

root

然后我们完成了。我们将控制传递给Tkinter,后者完成剩下的工作。

答案 1 :(得分:2)

Twisted是采用异步方法设计的。你的程序会导致某些事情发生,但它不会等待那件事发生,而是将控制权传递给扭曲的事件循环(扭曲的说法中的'reactor')。当反应堆发现某些东西需要你注意时,它将使用你最初调用该动作时提供的“回调”来调用你的程序。基本工作流程如下所示。首先,

something_deferred = make.twisted.do.something()

something_deferred通常是twisted.internet.defer.Deferred个实例,代表something()的结果。通常,something()需要一些时间才能完成,因此即使something()立即返回,延迟对象也没有结果。那么你需要做的是定义一个函数,一旦结果准备好就可以调用twisted。

def something_callback(result):
    do_something_else(result)

在大多数情况下,您还应该定义一个函数来处理something()中发生错误的情况,

def something_errback(fault):
    cleanup_something()

最后,当something()最终准备好时,你必须告诉你想让它使用这些功能。

something_deferred.addCallbacks(something_callback, something_errback)

请注意,您不会自行调用这些函数,只需将其名称传递给addCallbacks()即可。 Twisted本身负责调用你的函数。

并非每个示例都遵循此确切模式,但在大多数情况下,您将实例方法放在实现扭曲定义接口的类中,或者将可调用函数传递给生成事件的扭曲函数。

答案 2 :(得分:2)

“好莱坞原则”之所以如此命名,是因为在好莱坞的电影界,紧张的第一次演员有时会在试镜后一遍又一遍地打电话给工作室,看他们是否得到了这个部分。在软件开发中,我们称之为polling,而且效率极低。在好莱坞的比喻中,它甚至浪费了成功的申请人的时间(因为他们可能在选择之前反复调用)并且浪费了工作室的时间(因为许多未被选中的应用程序仍会称之为)。

这是一个Python文件,希望能够阐明实际的原则:

首先,我们有一个Actor,可以为试镜表演或获得一部分:

class Actor(object):
    def __init__(self, name):
        self.name = name

    def youGotThePart(self):
        print self.name, "got the part."

    def perform(self):
        print self.name, "performs an audition."

然后,我们有铸造过程:

applicants = []
def audition(actor):
    actor.perform()
    applicants.append(actor)

def cast():
    import random
    selection = random.choice(applicants)
    selection.youGotThePart()

试镜要求演员表演,当演员发生时,选择演员(随机 - 作为好莱坞演员的非参与者,我怀疑这可能是最真实的模拟)。那个演员然后得到通知(工作室“称他们”)。

最后,这是整个铸造过程:

alice = Actor("alice")
bob = Actor("bob")
carol = Actor("carol")
dave = Actor("dave")

audition(alice)
audition(bob)
audition(carol)
audition(dave)

cast()

如您所见,这非常简单,不涉及GUI或网络或任何其他外部输入源。它只是构建代码的一种方法,以避免浪费检查和重新检查相同的状态。如果您考虑将此程序构造为 not ,请遵循相关原则,您将得到如下循环:

while True:
    for actor in alice, bob, carol, dave:
        if actor.didIGetThePart():
            break
    maybeGiveSomeoneThePart()

这当然是非常浪费的,因为谁知道演员在工作室选择之前可以拨打多少次电话?