web-dev-qa-db-fra.com

Modèles de conception à éviter

Beaucoup de gens semblent d'accord pour dire que le modèle Singleton présente un certain nombre d'inconvénients et certains suggèrent même d'éviter complètement le modèle. Il y a un excellente discussion ici . Veuillez adresser tout commentaire sur le modèle Singleton à cette question.

Ma question : Existe-t-il d'autres modèles de conception à éviter ou à utiliser avec grand soin?

105
Brian Rasmussen

Les modèles sont complexes

Tous les modèles de conception doivent être utilisés avec soin. À mon avis vous devriez refactoriser vers les modèles quand il y a une raison valable de le faire au lieu d'implémenter un modèle immédiatement. Le problème général de l'utilisation de modèles est qu'ils ajoutent de la complexité. La surutilisation des modèles rend une application ou un système donné difficile à développer et à maintenir.

La plupart du temps, il existe une solution simple et vous n'aurez pas besoin d'appliquer de modèle spécifique. Une bonne règle d'or consiste à utiliser un modèle chaque fois que des morceaux de code ont tendance à être remplacés ou à changer souvent et à être prêts à faire face à la mise en garde d'un code complexe lors de l'utilisation d'un modèle.

N'oubliez pas que votre objectif doit être la simplicité et utilisez un modèle si vous voyez un besoin pratique de prendre en charge le changement dans votre code.

Principes sur les modèles

Utiliser des modèles peut sembler inutile s'il peut évidemment conduire à des solutions trop complexes et sur-conçues. Cependant, il est au contraire beaucoup plus intéressant pour un programmeur de lire les techniques et principes de conception qui jettent les bases de la plupart des modèles. En fait, l'un de mes livres préférés sur les "modèles de conception" le souligne en réitérant les principes applicables au modèle en question. Ils sont assez simples pour être utiles que les modèles en termes de pertinence. Certains des principes sont suffisamment généraux pour englober plus que la programmation orientée objet (POO), tels que Liskov Substitution Principle , tant que vous pouvez créer des modules de votre code.

Il existe une multitude de principes de conception, mais ceux décrits dans le premier chapitre du livre du GoF sont très utiles pour commencer.

  • Programmer vers une 'interface', pas une 'implémentation'. (Gang of Four 1995: 18)
  • Privilégiez la "composition d'objet" à "l'héritage de classe". (Gang of Four 1995: 20)

Laissez-les vous pénétrer un moment. Il convient de noter que lorsque GoF a été écrit, un interface signifie tout ce qui est une abstraction (ce qui signifie également des super classes), à ne pas confondre avec l'interface en tant que type dans Java ou C #. Le deuxième principe vient de la surutilisation observée de l'héritage qui est malheureusement encore courant aujourd'hui .

De là, vous pouvez lire principes SOLIDES qui a été rendu public par Robert Cecil Martin (alias. Oncle Bob) . Scott Hanselman a interviewé l'oncle Bob dans un podcast sur ces principes :

  • [~ # ~] s [~ # ~] ingle Principe de responsabilité
  • [~ # ~] o [~ # ~] stylo Principe fermé
  • [~ # ~] l [~ # ~] Principe de substitution iskov
  • [~ # ~] i [~ # ~] Principe de ségrégation d'interface
  • [~ # ~] d [~ # ~] Principe d'inversion de dépendance

Ces principes sont un bon début pour lire et discuter avec vos pairs. Vous pouvez constater que les principes s'entrelacent les uns avec les autres et avec d'autres processus tels que séparation des préoccupations et injection de dépendance . Après avoir fait TDD pendant un certain temps, vous pouvez également constater que ces principes viennent naturellement dans la pratique car vous devez les suivre dans une certaine mesure afin de créer isolated et répétable tests unitaires.

148
Spoike

Celui qui inquiète le plus les auteurs de Design Patterns est le modèle "Visitor".

C'est un "mal nécessaire" - mais il est souvent sur-utilisé et la nécessité de celui-ci révèle souvent une faille plus fondamentale dans votre conception.

Un autre nom pour le modèle "Visiteur" est "Envoi multiple", car le modèle Visiteur correspond à ce que vous vous retrouvez lorsque vous souhaitez utiliser un envoi de type unique OO langue pour sélectionner le code à utiliser en fonction du type de deux (ou plus) objets différents.

L'exemple classique étant que vous avez l'intersection entre deux formes, mais il y a un cas encore plus simple qui est souvent négligé: comparer l'égalité de deux objets hétérogènes.

Quoi qu'il en soit, vous vous retrouvez souvent avec quelque chose comme ça:

interface IShape
{
    double intersectWith(Triangle t);
    double intersectWith(Rectangle r);
    double intersectWith(Circle c);
}

Le problème avec ceci est que vous avez couplé toutes vos implémentations de "IShape". Vous avez laissé entendre que chaque fois que vous souhaitez ajouter une nouvelle forme à la hiérarchie, vous devrez également modifier toutes les autres implémentations "Shape".

Parfois, c'est la conception minimale correcte - mais réfléchissez bien. Est-ce que votre conception vraiment vous oblige à expédier sur deux types? Êtes-vous prêt à écrire chacune des explosions combinatoires de multi-méthodes?

Souvent, en introduisant un autre concept, vous pouvez réduire le nombre de combinaisons que vous devrez réellement écrire:

interface IShape
{
    Area getArea();
}

class Area
{
    public double intersectWith(Area otherArea);
    ...
}

Bien sûr, cela dépend - parfois, vous avez vraiment besoin d'écrire du code pour gérer tous ces différents cas - mais cela vaut la peine de faire une pause et de réfléchir avant de plonger et d'utiliser Visitor. Cela pourrait vous faire économiser beaucoup de douleur plus tard.

21
Paul Hollingsworth

Singletons - une classe utilisant singleton X a une dépendance qui est difficile à voir et difficile à isoler pour les tests.

Ils sont utilisés très souvent car ils sont pratiques et faciles à comprendre, mais ils peuvent vraiment compliquer les tests.

Voir Les singletons sont des menteurs pathologiques .

16
orip

Je crois que le modèle de méthode de modèle est généralement un modèle très dangereux.

  • Souvent, il utilise votre hiérarchie d'héritage pour "les mauvaises raisons".
  • Les classes de base ont tendance à être jonchées de toutes sortes de codes non liés.
  • Cela vous oblige à verrouiller la conception, souvent très tôt dans le processus de développement. (Verrouillage prématuré dans de nombreux cas)
  • Changer cela plus tard devient de plus en plus difficile.
14
krosenvold

Je ne pense pas que vous devriez éviter les modèles de conception (DP), et je ne pense pas que vous devriez vous forcer à utiliser des DP lors de la planification de votre architecture. Nous ne devons utiliser les PDD que lorsqu'ils émergent naturellement de notre planification.

Si nous définissons dès le départ que nous voulons utiliser un DP donné, nombre de nos futures décisions de conception seront influencées par ce choix, sans aucune garantie que le DP que nous avons choisi est adapté à nos besoins.

Une chose que nous ne devrions pas non plus faire est de traiter un PDD comme une entité immuable, nous devons adapter le modèle à nos besoins.

Donc, en résumé, je ne pense pas que nous devrions éviter les PDD, nous devrions les embrasser lorsqu'ils prennent déjà forme dans notre architecture.

9
Megacan

Je pense qu'Active Record est un modèle surutilisé qui encourage à mélanger la logique métier avec le code de persistance. Il ne fait pas un très bon travail pour masquer l'implémentation de stockage de la couche modèle et lie les modèles à une base de données. Il existe de nombreuses alternatives (décrites dans PoEAA) telles que Table Data Gateway, Row Data Gateway et Data Mapper qui offrent souvent une meilleure solution et contribuent certainement à fournir une meilleure abstraction au stockage. De plus, votre modèle ne doit pas besoin être stocké dans une base de données; qu'en est-il de les stocker au format XML ou d'y accéder à l'aide de services Web? Serait-il facile de changer le mécanisme de stockage de vos modèles?

Cela dit, Active Record n'est pas toujours mauvais et est parfait pour les applications plus simples où les autres options seraient exagérées.

7
Tim Wardle

C'est simple ... évitez les modèles de conception qui ne sont pas clairs pour vous ou ceux que vous ne vous sentez pas à l'aise dans .

Pour n'en nommer que quelques-uns ...

il y a des modèles peu pratiques , comme par exemple:

  • Interpreter
  • Flyweight

il y en a aussi plus difficiles à saisir , comme par exemple:

  • Abstract Factory - Le modèle d'usine abstrait complet avec les familles d'objets créés n'est pas un jeu d'enfant comme il semble l'être
  • Bridge - Peut devenir trop abstrait, si l'abstraction et l'implémentation sont divisées en sous-arbres, mais est un modèle très utilisable dans certains cas
  • Visitor - La compréhension du mécanisme de double répartition est vraiment un MUST

et il y a des modèles qui semblent terriblement simples , mais ne sont pas un choix si clair pour diverses raisons liées à leur principe ou à leur mise en œuvre:

  • Singleton - modèle pas vraiment totalement mauvais, juste TROP surutilisé (souvent là, où il ne convient pas)
  • Observer - excellent modèle ... rend le code beaucoup plus difficile à lire et à déboguer
  • Prototype - le compilateur vérifie le dynamisme (qui peut être bon ou mauvais ... cela dépend)
  • Chain of responsibility - trop souvent juste forcé/artificiellement poussé dans la conception

Pour ces "peu pratiques", il faut vraiment réfléchir avant de les utiliser, car il existe généralement une solution plus élégante quelque part.

Pour les "plus difficiles à saisir" ... ils sont vraiment d'une grande aide, lorsqu'ils sont utilisés à des endroits appropriés et lorsqu'ils sont bien mis en œuvre ... mais ils sont cauchemardesques, lorsqu'ils sont mal utilisés.

Maintenant, quelle est la prochaine ...

6
Marcel Toth

J'espère que je ne serai pas trop battu pour ça. Christer Ericsson a écrit deux articles ( n , deux ) sur le thème des modèles de conception dans son blog de détection de collision en temps réel . Son ton est plutôt dur, et peut-être un peu provocateur, mais l'homme connaît son affaire, donc je ne le rejetterais pas comme un délire de fou.

5
falstro

Certains disent que localisateur de service est un anti motif.

5
Arnis Lapsa

Je crois que le modèle d'observateur a beaucoup à répondre, il fonctionne dans des cas très généraux, mais comme les systèmes deviennent plus complexes, il devient un cauchemar, nécessitant des notifications OnBefore (), OnAfter (), et souvent l'affichage de tâches asynchrones pour éviter entrée. Une bien meilleure solution consiste à développer un système d'analyse automatique des dépendances qui instrumente tous les accès aux objets (avec des barrières de lecture) pendant les calculs et crée automatiquement un Edge dans un graphique de dépendance.

2
Jesse Pepper

Un complément au message de Spoike, Refactoring to Patterns est une bonne lecture.

2
Adeel Ansari

Iterator est un autre modèle GoF à éviter, ou du moins à ne l'utiliser que lorsqu'aucune alternative n'est disponible.

Les alternatives sont:

  1. pour chaque boucle. Cette construction est présente dans la plupart des langues courantes et peut être utilisée pour éviter les itérateurs dans la majorité des cas.

  2. sélecteurs à la LINQ ou jQuery. Ils doivent être utilisés lorsque for-each n'est pas approprié car tous les objets du conteneur ne doivent pas être traités. Contrairement aux itérateurs, les sélecteurs permettent de manifester en un seul endroit quels types d'objets doivent être traités.

0
Volodymyr Frolov