Les modèles ne doivent être utilisés que lorsqu'ils peuvent être la meilleure solution ou aider à la création d'une bonne solution (êtes-vous d'accord?).
Je vois les modèles de conception strictement comme des détails d'implémentation. Si vous documentez vos API publiques et votre programme dans cette documentation, en général, peu importe (ou vous affectera beaucoup) où vous avez des modèles de conception. Autrement dit, vous n'allez pas "J'ai un modèle de pont ici, et je vais implémenter un visiteur en plus". Au lieu de cela, c'est "cette classe aura différentes implémentations sur différents systèmes d'exploitation, donc elle sera implémentée en utilisant un modèle de pont". Ensuite, lorsque vous l'utilisez, vous êtes indifférent à sa mise en œuvre en tant que pont - car vous regardez l'API publique, pas un modèle de pont.
combien d'efforts doit-on réellement investir pour créer des conceptions flexibles à couplage lâche?
Un couplage lâche peut être obtenu en suivant un ensemble simple de règles. Si vous les respectez, votre code sera (plus) faiblement couplé au fur et à mesure que vous l'écrivez (c'est-à-dire que tout effort fait déjà partie du processus de développement).
Parmi les règles (liste non exhaustive):
- définir vos interfaces en pensant (ou en écrivant) le code client (comment la classe sera utilisée), pas ce que la classe fera (c'est-à-dire concevoir l'interface, pas l'implémentation)
- "dis, ne demande pas"
- construire des objets à partir de pièces déjà créées
- passez dans le constructeur les objets réels que vous utiliserez (pas les usines pour les membres, les paramètres pour les usines des paramètres, ou quelque chose comme ça).
- SEC (si vous avez deux lignes qui apparaissent dans le même ordre à deux endroits, extrayez-les dans une fonction distincte et ainsi de suite).
- Si la création d'un objet est une opération plus complexe, implémentez la création des pièces intermédiaires en tant que méthode / classe d'usine (c'est-à-dire pas dans le corps du constructeur).
- YAGNI (créez des choses comme vous en avez besoin, pas avant).
Ces règles sont suivies différemment, selon la langue, la méthodologie de développement suivie par votre équipe (par exemple TDD), les contraintes de budget temps, etc.
Par exemple, en Java, il est recommandé de définir votre interface en tant que interface
et d'écrire du code client dessus (puis instancier l'interface avec une classe d'implémentation).
En C ++ d'autre part, vous n'avez pas d'interfaces, vous ne pouvez donc écrire que l'interface en tant que classe de base abstraite; Étant donné qu'en C ++ vous n'utilisez l'héritage que lorsque vous en avez une forte exigence (et évitez ainsi la surcharge de fonctions virtuelles inutiles), vous ne définirez probablement pas l'interface séparément, juste l'en-tête de classe).
Ceux qui s'opposent aux modèles de conception affirment que les coûts d'utilisation de ces modèles l'emportent souvent sur les avantages.
Je pense qu'ils le font mal. Si vous écrivez du code faiblement couplé (et SEC), l'intégration de modèles de conception dans celui-ci entraîne un effort supplémentaire minimal. Sinon, vous devrez adapter votre code pour implémenter un modèle de conception.
Si vous devez apporter de nombreuses modifications pour implémenter un modèle de conception, votre problème n'est pas le modèle de conception - c'est votre base de code étant monolithique et étroitement couplée. Il s'agit d'un problème de conception incorrect / sous-optimal, pas d'un problème de modèles de conception.
Ce que j'aimerais savoir, c'est combien d'efforts devrais-je réellement consacrer à la création de niveaux supplémentaires d'abstraction et de conceptions, uniquement pour permettre à mon application de suivre les principes OO tels que le couplage lâche, la programmation à une interface, etc. il? Combien d'efforts dois-je y consacrer?
Vos questions supposent (non déclaré) que le seul avantage du couplage lâche est la possibilité de mettre en œuvre facilement des modèles de conception. Ce n'est pas.
Parmi les avantages du couplage lâche, citons:
- refactorisation et refonte de la flexibilité
- moins d'efforts gaspillés
- testabilité
- possibilité accrue de réutiliser le code
- simplicité de conception
- moins de temps passé dans le débogueur
... et quelques autres qui ne me viennent pas à l'esprit en ce moment.