2015-08-11 4 views
1

Je voudrais consulter un morceau de code avec vous. J'ai:Refactoring si des instructions en python

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

Et là j'ai 27 if/elifs. Normalement, j'irais dans le répartiteur de carte - fonction, mais après chaque if/elif j'ai deux lignes de code avec le même dictionnaire référence. Me suggérez-vous une solution propre pour remplacer ces constructions laides? Créer 27 classes pour appliquer le polymorphisme ou 27 fonctions ne sonne pas bien ... qu'en pensez-vous?

+0

Utilisez une table de hachage (un dictionnaire avec des méthodes comme valeurs) – muddyfish

+0

Merci pour votre réponse. Mais alors je devrais créer 27 fonctions. Y a-t-il une meilleure solution? – Konrad

+0

Vous pouvez utiliser lambdas avec des instructions séparées par ';' 's si vous avez vraiment besoin de – muddyfish

Répondre

1

Vous pouvez inclure les informations méta dans vos énumérations, si cela est ok pour vous code client, ce qui signifie que vous possédez les énumérations. Voici un exemple:

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

et d'avoir une seule fonction pour gérer vos opérations:

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

Ceci est en supposant que vous utilisez le Enum que vous aviez dans l'une de vos questions. Dans ce cas, vous devrez ajouter une ligne là:

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) 

Ensuite, vous aurez pas besoin de contrôles de cas, simplement:

handle_operation(tuple_type) 
+0

La fonction à appeler je suppose -' self.klass = valeur [2] ' – muddyfish

+1

' operation.klass 'est l'attribut' Enum' (déjà mis à jour), qui représente l'instance de classe à initialiser pour chaque type d'opération. – bagrat

3

Vous avez raison, une cartographie est la voie à suivre. Utilisez getattr pour accéder à une méthode de son nom:

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

Peut-être que vous pouvez représenter l'opération avec un dict ou Tupple, comme

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

alors vous pouvez y accéder comme

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

L'utilisation de 'globals' est hackish –