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
Je pense que cela dépendra de la fréquence/ce que vous utilisez f() pour –
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
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. –