Dans notre application Rails, nous ajoutons des notifications. Certains d'entre eux sont blocking
: Ils arrêtent la progression de la ressource sur laquelle ils sont ajoutés, car certaines informations sur cette ressource sont manquantes.
Les autres notifications sont de simples notifications et ne fournissent que des informations.
Aujourd'hui, j'ai eu une discussion avec un autre programmeur de notre équipe. J'ai créé la structure d'héritage comme ceci:
Cependant, il préfère que j'ajoute simplement blocking
une méthode de retour booléen sur chaque notification et spécifie une liste de sous-classes qui bloquent la classe parent Notification.
La différence entre ces approches n'est pas très grande; dans mon approche, il n'est pas nécessaire de spécifier cette liste, en gardant la classe racine plus propre. D'un autre côté, la logique spéciale qui se produit Notification::Blocking
actuellement n'est pas très grande non plus.
Quel type d'abstraction convient le mieux à ce problème?
Réponses:
Vous voulez éviter que les classes de base connaissent les classes dérivées. Il introduit un couplage étroit et est un casse-tête de maintenance car vous devez vous rappeler d'ajouter à la liste chaque fois que vous créez une nouvelle classe dérivée.
Cela vous empêchera également de pouvoir placer la classe Notification dans un package / assembly réutilisable si vous souhaitez utiliser cette classe dans plusieurs projets.
Si vous voulez vraiment utiliser une seule classe de base, une autre façon de résoudre ce problème consiste à ajouter une propriété ou une méthode virtuelle IsBlocking sur la classe Notification de base. Les classes dérivées pourraient alors remplacer cela pour retourner vrai ou faux. Vous auriez une solution à classe unique sans que la classe de base ne connaisse les classes dérivées.
la source
Cela semble très particulier et est une odeur de code particulière.
Je fournirais des sous-classes si vous avez des différences de comportement entre les classes et que vous souhaitez traiter toutes ces notifications de la même manière (c'est-à-dire en utilisant le polymorphisme ).
la source
À l'inverse des réponses existantes, je suggérerais que la propriété booléenne est la meilleure option si le mode à utiliser doit être changé dynamiquement (par exemple via un fichier de configuration qui donne une liste des types à bloquer). et qui ne le sont pas).
Cela dit, une meilleure conception, même dans cette situation, pourrait être d'utiliser un objet Decorator.
la source
Je dirais que cela dépend de ce qui est spécial à propos d'une notification de blocage, bien que ma première pensée soit d'aller avec "les deux":
De cette façon, vous pouvez utiliser
n.Blocking
oun is BlockingNotification
(tout en pseudo-code), bien que, si vous allez autoriser une classe à implémenter uneBlocking
valeur contextuelle , vu que vous devrez vérifier cette valeur à chaque fois, laBlockingNotification
classe devient moins utile.Dans tous les cas, je suis d'accord avec les autres réponses selon lesquelles vous ne voulez pas que l'implémentation de la classe de base
Blocking
connaisse les classes dérivées.la source
Au lieu de créer deux classes de base et plusieurs instances de chacune, créez une classe de notification avec un booléen pour indiquer si la notification est bloquante et toute autre information nécessaire pour communiquer la notification à l'utilisateur.
Cela vous permet d'utiliser un seul ensemble de codes pour le traitement et la présentation des notifications et réduit la complexité de votre code.
la source