кто-нибудь может дать простой питон для объяснения "голливудского принципа" / инверсии контроля - PullRequest
2 голосов
/ 17 июня 2011

Мне очень интересен веб-фреймворк Twisted. Насколько я знаю рамки использует принцип Голливуда. Я просто знаю термин, но совершенно не имею Идея об этом шаблоне дизайна. Я сделал много поиска в Google по реализации Голливудский принцип в Python. Но результатов было мало. Может ли кто-нибудь показать мне простой код на Python, описывающий этот шаблон проектирования?

Ответы [ 3 ]

6 голосов
/ 17 июня 2011

Я на самом деле никогда не слышал фразы «Голливудский принцип» раньше, и я не знаком с Twisted (хотя я чувствую, что должен быть). Но концепция инверсии управления не так сложна. Я думаю, что программирование GUI - хороший способ представить это. Рассмотрим следующее из здесь (слегка изменено).

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()

Это очень простой пример инверсии управления. Он использует обратных вызовов - отсюда и голливудский принцип прозвище (спасибо Свену за ссылку). Идея в том, что вы пишете функцию, но никогда не вызываете ее. Вместо этого вы передаете его другой программе и сообщаете этой программе, когда ее вызывать. Затем вы даете контроль над этой программой. Вот подробное объяснение кода:

import Tkinter

class App(object):

Мы начнем с определения класса, который будет хранить наши обратные вызовы и передавать их соответствующим частям того, что я назову «основной программой».

    def __init__(self, master):

Нашему классу нужна «магистерская программа»; главная программа - это то, что будет вызывать функции, которые мы определяем. В данном случае это корневое окно графического интерфейса. Более правильно, в контексте программирования GUI, мы можем сказать, что master является родительским из frame.

        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 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 в качестве его родителя.

root.mainloop()

И тогда мы закончили. Мы передаем контроль Tkinter, который выполняет всю остальную работу.

2 голосов
/ 19 июня 2011

«Голливудский принцип» назван так, потому что в киноиндустрии в Голливуде нервные начинающие актеры иногда снова и снова звонят в студию после прослушивания, чтобы узнать, получат ли они роль. В разработке программного обеспечения мы называем это опросом , и это супер неэффективно. В метафоре Голливуда это тратит впустую даже время успешного кандидата (потому что они могут повторно звонить до того, как будет сделан выбор), и это тратит время студий (потому что многие приложения, которые не были выбраны, тем не менее будут вызывать их).

Вот файл 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()

Как видите, это очень просто и не включает в себя графический интерфейс, сети или любые другие внешние источники ввода. Это просто способ структурировать ваш код, чтобы избежать бесполезной проверки и повторной проверки того же состояния. Если вы подумаете о структурировании этой программы, чтобы не следовали указанному принципу, у вас получился бы цикл примерно такой:

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

что, конечно, очень расточительно, так как кто знает, сколько раз актеры могли сделать эти звонки, прежде чем студия выберет?

2 голосов
/ 18 июня 2011

Twisted разработан с асинхронным подходом.Ваша программа заставляет что-то происходить, но вместо того, чтобы ждать, пока это произойдет, она передает управление обратно в витую петлю событий («реактор» на витой речи).Когда реактор обнаружит, что что-то требует вашего внимания, он вызовет вашу программу с «обратным вызовом», который вы указали, когда первоначально вызывали действие.Основной рабочий процесс выглядит следующим образом.Во-первых,

something_deferred = make.twisted.do.something()

something_deferred обычно является экземпляром twisted.internet.defer.Deferred, который представляет результат something().Обычно для завершения something() требуется некоторое время, и поэтому у отложенного объекта еще нет результатов, даже если something() сразу возвращается.Затем вам нужно определить функцию, которую twisted может вызывать, когда результат действительно будет готов.

def something_callback(result):
    do_something_else(result)

В большинстве случаев вам также следует определить функцию, которая обрабатывает случай, когда в * произошла ошибка1012 *,

def something_errback(fault):
    cleanup_something()

Наконец, вы должны сказать twisted, что хотите, чтобы он использовал эти функции, когда something() наконец готов.

something_deferred.addCallbacks(something_callback, something_errback)

Обратите внимание, что вы этого не делаетевызывайте функции самостоятельно, просто передавайте их имена addCallbacks().Twisted сам отвечает за вызов ваших функций.

Не каждый пример следует этому точному шаблону, но в большинстве случаев вы помещаете метод экземпляра в класс, который реализует интерфейс с определенным витым интерфейсом, или передаете вызываемый объект витым функциям.которые производят события.

...