2

I would like to consult some piece of code with you. I have:

if tuple_type == Operation.START_SERVER:
    dictionary = ServersDictionary()
    dictionary.start(some_param)
elif tuple_type == Operation.STOP_SERVER:
    dictionary = ServersDictionary()
    dictionary.stop(some_param)
(...)
elif tuple_type == Operation.START_APP:
    dictionary = AppsDictionary()
    dictionary.start(some_param)
elif ...
(....)

And there I have 27 if / elifs. Normally, I would go into map - function dispatcher, but after every if / elif I have two lines of code with same dictionary reference. Would you suggest me some clean solution to replace those ugly constructions?

Creating 27 classes for applying polymorphism or 27 functions doesn't sound good... what do you think?

9
  • Use a hash table (a dictionary with methods as values) Commented Aug 11, 2015 at 8:17
  • Thanks for reply. But then I would need to create 27 functions. Is there any better solution? Commented Aug 11, 2015 at 8:22
  • You could use lambdas with statements seperated by ;'s if you really needed to Commented Aug 11, 2015 at 8:23
  • are your some_params different for all cases? Commented Aug 11, 2015 at 8:25
  • 1
    If the complexity is essential, the only question is where you want the complexity to appear. Yes, you can move it into a dict or a module or whatever but it is still there. If the complexity is not essential, then there is a pattern which allows you to simplify the complexity, but perhaps a cost for using the simplification -- such as being less flexible in the future. Commented Aug 11, 2015 at 8:27

3 Answers 3

5

You're right, a mapping is the way to go. Use getattr to access a method from its name:

mapping = {Operation.START_SERVER: (ServerDictionary, 'start', some_param),
           Operation.STOP_SERVER: (ServerDictionary, 'stop', some_param),
           Operation.START_APP: (AppsDictionary, 'start', some_param)}
...
cls, method, param = mapping[tuple_type]
dictionary = cls()
getattr(dictionary, method)(param)
Sign up to request clarification or add additional context in comments.

Comments

2

You can enclose the meta info into your enums, if that is ok for you client code, meaning that you own the enums. Here is an example:

class Operation(Enum):
    START_SERVER = (0, "start", ServersDictionary)
    STOP_SERVER = (1, "stop", ServersDictionary)
    START_APP = (1, "start", AppsDictionary)

And then have a single function to handle your operations:

def handle_operation(operation, some_param):
    klass = operation.klass
    dictionary = klass()
    fn = getattr(dictionary, operation.value)
    fn(some_param)

This is assuming you are using the Enum you had in one of your questions. In that case, you will need to add one line there:

class Enum(object):
    __metaclass__ = EnumMeta

    def __init__(self, value):
        super(Enum, self).__init__()

        self.value, self.repr, self.klass = value[0], value[1], value[2]

    def __repr__(self):
        return str(self.repr)

Then you will not need any case checks, simply:

handle_operation(tuple_type)

2 Comments

The function to call i assume - self.klass = value[2]
operation.klass is the Enum attribute (already updated the answer), which represents the class instance to be initialised for each operation type.
1

Maybe you can represent the operation with a dict or tupple, like

op = {'target': 'Servers', 'action': 'start', 'params': (arg1, arg2)}

then you can access it like

obj = globals()[op['target']+'Dictionary']()
getattr(obj, op['action'])(*op['params'])

1 Comment

Using globals is hackish

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.