简体   繁体   中英

Patterns - Event Dispatcher without else if?

I'm creating a Python wrapper for the Detours library. One piece of the tool is a dispatcher to send all of the hooked API calls to various handlers.

Right now my code looks like this:

if event == 'CreateWindowExW':
    # do something
elif event == 'CreateProcessW':
    # do something
elif ...

This feels ugly. Is there a pattern to create an event dispatcher without my having to create an elif branch for each Windows API function?

One nice way to do this is to define a class which has methods equating to the relevant API function names, plus a dispatch method which dispatches to the correct method. For example:

class ApiDispatcher(object):

    def handle_CreateWindowExW(self):
        # do whatever

    def handle_CreateProcessW(self):
        # do this one

    def dispatch(self, event):
        method = getattr(self, 'handle_%s' % event)
        method()

Those if's will eventually have to go somewhere. Why not do it like this:

handler = get_handler(event)
handler.process()

and in the get_handler you'd have your ifs, each returning an object which does its work in the process method.

An alternative would be a map to callables, like this:

def react_to_create_window_exw():
   # do something with event here
   pass

handlers = {
  "CreateWindowExW" : react_to_create_window_exw
}

and you would use it like this:

handler = handlers[event]
handler()

This way you would not use any if/else conditions.

You can use the dispatch dict method.

def handle_CreateWindowExW():
    print "CreateWindowExW"     
    #do something

events = {
    "CreateWindowExW": handle_CreateWindowExW
}

events[event]()

This way, you can just add events without having to add different if statements.

Usually in such cases when you have a predefined list of actions to take, use a map eg

def CreateWindowExW():
    print 'CreateWindowExW'

def CreateProcessW():
    print 'CreateProcessW'

action_map = {
    'CreateWindowExW': CreateWindowExW,
    'CreateProcessW': CreateProcessW
}

for action in ['CreateWindowExW', 'UnkownAction']:
    try:
        action_map[action]()
    except KeyError:
        print action, "Not Found"

Output:

CreateWindowExW
UnkownAction Not Found

so using a map you can create a very powerful dispatcher

I didn't find anything that was as graceful as it could be in this area, so I wrote something that let's you do:

from switcheroo import Switch, default

switch = Switch({
    'foo': lambda x: x+1,
    default: lambda x: x-1,
})

>>> switch['foo'](1)
2
>>> switch['bar'](1)
0

There are some other flavours; docs are here , code is on github , package is on pypi .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM