2015-10-08 3 views
1

Par exemple je peux créer deux modules (Mod1 et Mod2) qui ont f(). Ou je peux créer deux classes qui implémentent f().Avantages pour deux modules avec la même interface ou deux classes avec la même interface?

je peux alors soit

if condition: 
    import Mod1 as m 
else: 
    import Mod2 as m 

m.f() 

ou

if condition: 
    m = Class1() 
else: 
    m = Class2() 
m.f() 

Il est évident que si je veux stocker tout état dans lequel je dois utiliser des classes, mais si je suis juste en utilisant des méthodes de classe, y at-il des avantages à l'une ou l'autre méthode par rapport à l'autre?

EDIT: Je suis principalement préoccupé par la maintenabilité/l'extensibilité/la lisibilité et non par les performances d'exécution.

+0

Je pense que cela dépendra de la fréquence/ce que vous utilisez f() pour –

+0

Dans ce cas précis, je vais probablement appelle chaque méthode juste une fois, mais je suis également curieux au sujet d'un cas général. – Presto

+0

Je pense qu'en général, vous créez les modules, pas la classe simplement parce qu'une classe est normalement associée à la création d'instances d'objets avec des attributs, des méthodes de classe, etc. plutôt que seulement pour les fonctions. –

Répondre

2

General Idea

Dans votre cas, vous pouvez aller avec fonction simple niveau du module, ne pas surcharger tout. Mais dans la mesure où vous êtes intéressé par le cas général, je vous recommande d'aller avec le Abstract Factory pattern. Voici un exemple de solution pour vous:

class YourAbstractFactory(object): 
    @classmethod 
    def get_factory(cls, condition): 
     cond_map = { 
      'impl1': Impl1, 
      'impl2': Impl2 
     } 

     impl = cond_map.get(condition) 

     return impl() if impl else None 

    def f1(self): 
     pass 

    def f2(self): 
     pass 

YourAbstractFacotry classe est évidemment une classe abstraite, qui définit simplement l'interface à mettre en œuvre, à savoir la collecte de vos f fonctions. De plus, il définit et implémente la méthode de classe get_factory qui renvoie l'implémentation appropriée, en fonction de la condition.

class Impl1(YourAbstractFactory): 
    def f1(self): 
     print('Impl1.f1') 

    def f2(self): 
     print('Impl1.f2') 

class Impl2(YourAbstractFactory): 
    def f1(self): 
     print('Impl2.f1') 

    def f2(self): 
     print('Impl2.f2') 

Les classes ci-dessus sont les deux implémentations indépendantes de votre interface. Ils ne se connaissent pas et peuvent exister indépendamment. L'avantage de cette solution est que votre code client sera découplé de vos implémentations. C'est-à-dire que vous ne passerez que la condition et obtiendrez l'implémentation requise, et que vous n'avez aucune idée et dépendance de cette implémentation dans votre code client. La seule pièce qui est consciente des implémentations concrètes de l'interface est la méthode get_factory, qui est facile à entretenir.

Améliorations supplémentaires

Pour améliorer encore cette solution et d'augmenter la sécurité (bien que, Python est un langage pour les adultes;)), vous pouvez également utiliser le module abc, avec son ABCMeta métaclasse et abstractmethod décorateur, pour éviter initialiser des instances de classes qui n'implémentent pas toute l'interface. Dans ce cas, vous devrez définir votre classe d'usine comme ceci.

from abc import ABCMeta, abstractmethod 

class YourAbstractFactory(object): 
    __metaclass__ = ABCMeta 

    @classmethod 
    def get_factory(cls, condition): 
     cond_map = { 
      'impl1': Impl1, 
      'impl2': Impl2 
     } 

     impl = cond_map.get(condition) 

     return impl() if impl else None 

    @abstractmethod 
    def f1(self): 
     pass 

    @abstractmethod 
    def f2(self): 
     pass