web-dev-qa-db-fra.com

Comment adhérer au principe ouvert fermé dans la pratique

Je comprends l'intention du principe ouvert fermé. Il est destiné à réduire le risque de casser quelque chose qui fonctionne déjà tout en la modifiant, en vous indiquant d'essayer d'étendre sans modifier.

Cependant, j'ai eu du mal à comprendre comment ce principe est appliqué dans la pratique. À ma compréhension, il y a deux façons de l'appliquer. Beofore et après un changement possible:

  1. Avant: programme aux abstractions et "prédire l'avenir" autant que vous le pouvez. Par exemple, une méthode drive(Car car) devra modifier si Motorcycles sont ajoutés au système à l'avenir, de sorte qu'il viole probablement OCP. Mais la méthode drive(MotorVehicle vehicle) est moins susceptible de devoir changer à l'avenir, de sorte qu'il adhère à OCP.

    Cependant, il est assez difficile de prédire l'avenir et de connaître à l'avance quels changements seront apportés au système.

  2. Après: lorsqu'un changement est nécessaire, étendez une classe au lieu de modifier son code de courant.

La pratique n ° 1 n'est pas difficile à comprendre. Cependant, c'est la pratique n ° 2 que j'ai du mal à comprendre comment postuler.

Par exemple (je l'ai pris à partir d'une vidéo sur YouTube): disons que nous avons une méthode dans une classe qui accepte les objets CreditCard Objets: makePayment(CraditCard card). Un jour Vouchers sont ajoutés au système. Cette méthode ne les supporte pas, il doit donc être modifié.

Lors de la mise en œuvre de la méthode en premier lieu, nous n'avons pas réussi à prédire l'avenir et le programme de termes plus abstraits (par ex. makePayment(Payment pay), nous devons donc modifier le code existant.

La pratique n ° 2 dit que nous devrions ajouter la fonctionnalité en s'étendant au lieu de modifier. Qu'est-ce que cela signifie? Devrais-je sous-classer la classe existante au lieu de simplement modifier son code existant? Dois-je faire une sorte de wrapper autour de lui pour éviter la réécriture de code?

ou le principe ne se réfère même pas même à "comment modifier correctement/ajouter des fonctionnalités", mais fait plutôt référence à "Comment éviter de devoir modifier la première place (c'est-à-dire le programme aux abstractions)?

15
Aviv Cohn

Les principes de conception doivent toujours être équilibrés les uns contre les autres. Vous ne pouvez pas prédire l'avenir et la plupart des programmeurs le font horriblement quand ils essaient. C'est pourquoi nous avons le règle de trois , qui concerne principalement les doubles emplois, mais s'applique également à un refactoring pour tout autre des principes de conception.

Lorsque vous n'avez qu'une seule implémentation d'une interface, vous n'avez pas besoin de vous soucier de l'OCP, à moins que ce soit cristallin clair lorsque toutes les extensions auraient lieu. En fait, vous êtes souvent Perdre Clarté lorsque vous essayez de surfinir dans cette situation. Lorsque vous l'étendez une fois, vous refacteur pour le rendre sympathique OCP si C'est le moyen le plus simple et le plus clair de le faire. Lorsque vous l'étendez à une troisième mise en œuvre, vous veillez à le refroidir en tenant compte du PCF, même si cela nécessite un peu plus d'effort.

En pratique, lorsque vous n'avez que deux implémentations, refactoring lorsque vous ajoutez un tiers n'est généralement pas trop difficile. C'est quand vous le laissez passer au-delà de ce point qu'il devient gênant de maintenir.

14
Karl Bielefeldt

Je comprends l'intention du principe ouvert fermé. Il est destiné à réduire le risque de casser quelque chose qui fonctionne déjà tout en la modifiant, en vous indiquant d'essayer d'étendre sans modifier.

Il ne s'agit pas non plus de ne pas casser tous les objets qui s'appuient sur cette méthode en ne modifiant pas le comportement des objets déjà existants. Une fois qu'un objet a annoncé le comportement changeant, il est risqué car vous modifiez le comportement connu et prévu de l'objet sans savoir exactement quels autres objets s'attendent à ce comportement.

Qu'est-ce que ça veut dire? Devrais-je sous-classer la classe existante au lieu de simplement changer son code existant?

Ouais.

"Accepte uniquement les cartes de crédit" est défini dans le cadre du comportement de cette classe, via son interface publique. Le programmeur a déclaré au monde que la méthode de cette objet ne prend que des cartes de crédit. Elle l'a fait à l'aide d'un nom de méthode peu particulièrement claire, mais c'est fait. Le reste du système s'appuie sur cela.

Cela aurait pu avoir du sens à l'époque, mais maintenant s'il doit changer maintenant, vous devez faire une nouvelle classe qui accepte des choses autres que les cartes de crédit.

nouveau comportement = nouvelle classe

En tant que mis à part - Un bon moyen de prédire l'avenir est de penser au nom que vous avez donné une méthode. Avez-vous donné un nom de méthode de sonorité vraiment générale comme étant de rendement à une méthode avec des règles spécifiques dans la méthode quant à quel paiement il peut faire? C'est une odeur de code. Si vous avez des règles spécifiques, celles-ci doivent être définies à partir du nom de la méthode - L'annonce doit être maquillée. Faites cela lorsque vous écrivez l'objet la première fois et les autres programmeurs vous remercieront pour cela.

2
Cormac Mulhall

Je pense que vous avez l'air trop loin dans le futur. Résolvez le problème actuel de manière flexible qui adhère à ouvrir/fermé.

Disons que vous devez implémenter une méthode drive(Car car). En fonction de votre langue, vous avez quelques options.

  • Pour les langues qui prennent en charge la surcharge (C++), utilisez simplement drive(const Car& car)

    À un moment donné, vous pourriez avoir besoin de drive(const Motorcycle& motorcycle), mais cela n'interférera pas avec drive(const Car& car). Aucun problème!

  • Pour les langues qui ne prennent pas en charge la surcharge (objectif c), incluez le nom de type dans la méthode -driveCar:(Car *)car.

    À un moment donné, vous pourriez avoir besoin de -driveMotorcycle:(Motorcycle *)motorcycle, mais encore une fois, cela n'interférera pas.

Cela permet à drive(Car car) à fermer à la modification, mais est ouvert à l'extension à d'autres types de véhicules. Cette planification future minimaliste qui vous permet de faire du travail aujourd'hui, mais vous empêche de vous bloquer à l'avenir.

Essayer d'imaginer les types les plus élémentaires dont vous avez besoin peut conduire à une régression infinie. Que se passe-t-il lorsque vous voulez conduire une Segue, un vélo ou un jumbo jet. Comment construisez-vous un type de résumé générique unique qui peut rendre compte de tous les appareils que les personnes entrent et utilisent pour la mobilité?

2
Jeffery Thomas