Open Close Principle (OCP) vs Dependency Inversion Principle (DIP)

12

J'essayais de comprendre la différence entre le principe ouvert et fermé (OCP) et le principe d'inversion de dépendance (DIP).

Sur la base des recherches que j'ai faites sur Internet jusqu'à présent, je suis arrivé à la conclusion que «le DIP est une option grâce à laquelle nous pouvons atteindre l'OCP».

Ai-je raison là-dessus?

Pouvez-vous me donner un exemple qui ne suit pas DIP mais suit OCP?

Jitendar
la source

Réponses:

16

J'ai écrit une réponse précédemment sur le principe ouvert-fermé (OCP) vs le principe de substitution de Liskov (LSP) et ces deux principes se rapportent beaucoup, mais sont toujours conceptuellement différents avec quelques exemples artificiels d'avoir l'un mais pas l'autre. En raison de cette réponse, je ne parlerai que brièvement d'OCP et approfondirai DIP et ce qui fait que cela fonctionne.

Essayons de discuter de la façon dont l'OCP est lié et diffère du principe d'inversion de dépendance (DIP) en expliquant d'abord les différents principes.

Principe d'inversion de dépendance

En lisant les principes d'OOD de l'oncle Bob, vous constaterez que DIP indique ce qui suit:

Dépendent d'abstractions, pas de concrétions.

Une abstraction en Java est simplement réalisée avec les mots interface- abstractclés et , ce qui signifie que vous avez un "contrat" ​​pour une entité logicielle que le code doit suivre. Certains langages de programmation n'ont pas la possibilité de définir explicitement les comportements à suivre par le code, de sorte que les abstractions doivent être suivies de manière plus manuelle plutôt que de demander au compilateur de vous aider à appliquer le contrat. Par exemple, en C ++, vous avez des classes avec des méthodes virtuelles et des langages de programmation dynamiques tels que Javascript, vous devez vous assurer que vous utilisez les objets de la même manière (bien que dans le cas de Javascript, cela a été étendu en TypeScript qui ajoute un système de type pour vous aider avec des contrats d'écriture vérifiés par le compilateur).

Le nom inclut le terme "inversion" parce que traditionnellement (vous savez dans les vieux âges sombres de la programmation) vous écriviez des structures logicielles qui avaient des modules de niveau supérieur en fonction de modules de bas niveau. Par exemple, il était logique d'avoir ButtonAtKitchendes entrées de gestion pour a KitchenLamp1et KitchenLamp2. Malheureusement, cela a rendu le logiciel beaucoup plus spécifique qu'il ne devait l'être et le graphique d'objet ressemblerait à ceci:

ButtonAtKitchen gère KitchenLamp1 et KitchenLamp2

Donc quand vous rendez le logiciel plus général, en ajoutant des "contrats". Remarquez comment les flèches du graphique d'objet "inversent" la direction. Que les lampes de cuisine dépendent désormais d'un Button. En d'autres termes, les détails dépendent désormais des abstractions et non l'inverse.

KitchenButton a maintenant une abstraction IButton dont dépendent les lampes de cuisine

Ainsi, nous avons une définition plus générale de DIP, également détaillée dans l' article original de DIP par Oncle Bob .

A. Les modules de haut niveau ne doivent pas dépendre de modules de bas niveau. Les deux devraient dépendre de l'abstraction. B. Les abstractions ne devraient pas dépendre des détails. Les détails doivent dépendre des abstractions.

Principe ouvert-fermé

Suite aux principes de l'oncle Bob, vous constaterez que l'OCP déclare ce qui suit:

Vous devriez pouvoir étendre un comportement de classe sans le modifier.

Un exemple de cet objectif consiste à utiliser le modèle de stratégie dans lequel une Contextclasse est fermée pour modifications (c'est-à-dire que vous ne pouvez pas du tout changer son code interne) mais est également ouverte pour une extension via ses dépendances collaboratrices (c'est-à-dire les classes de stratégie).

Dans un sens plus général, tout module est conçu pour être extensible via ses points d'extension.

Un module avec des points d'extension

OCP est similaire à DIP, non?

Non , pas vraiment.

Bien qu'ils discutent tous les deux des abstractions, ils sont conceptuellement différents. Les deux principes examinent différents contextes, OCP sur un module particulier et DIP sur plusieurs modules. Vous pouvez réaliser les deux en même temps qu'avec la plupart des modèles de conception Gang of Four, mais vous pouvez toujours vous éloigner du chemin.

Dans l'exemple DIP mentionné ci-dessus, avec le bouton et les lampes de cuisine, aucune des lampes de cuisine n'est extensible (ni aucune exigence expliquant actuellement qu'elles doivent l'être). La conception brise l'OCP mais suit DIP .

Un exemple inversé (et artificiel) serait une lampe de cuisine extensible (le point d'extension étant quelque chose comme un LampShade), mais le bouton dépend toujours des lampes . Il casse DIP mais suit OCP .

Ne t'inquiète pas, ça arrive

C'est en fait quelque chose que vous verrez arriver souvent dans le code de production, dont une partie peut briser un principe. Dans les systèmes logiciels plus grands (c'est-à-dire quelque chose de plus grand que les exemples ci-dessus), vous pourriez casser un principe mais garder l'autre généralement parce que vous devez garder le code simple. C'est, à mon avis, correct pour les petits modules autonomes, car ils sont dans le contexte lié au principe de responsabilité unique (PRS).

Une fois que le module se complique un peu si vous avez besoin le plus susceptible de regarder avec tous les principes à l' esprit et redessiner ou factoriser à un certain modèle bien connu.

Spoike
la source