Open/Closed principle

Tags:    patterns

Hej,
Jeg sidder med et nyt hyggeprojekt, hvor jeg prøver at følge SOLID principperne.
I den forbindelse har jeg et spørgsmål angående Open/Closed pricippet.

Jeg har et interface, som bliver implementeret af en abstract klasse, hvor alle metoder er virtual (Jeg koder i C#)
Den klasse bliver så igen implementeret i en anden klasse.

Her kommer spørgsmålet så, så vidt jeg har forstået så må den anden klasse (Altså den der implementere den abstracte klasse) ikke ændres fremover men kun udvides i en ny klasse der nedarver fra den - er det korrekt?

Hvis ovenstående er korrekt, må jeg så overhovedet foretage ændringer i det generelle interface? Ændringerne der jo vil slå igennem i den abstakte klasse også.

Bonus spørgsmål; Såfremt der skal en ny klasse til for hver ændring, hvad vil være mest hensigtsmæssigt i forhold til navngivning?

På forhånd tak.





4 svar postet i denne tråd vises herunder
0 indlæg har modtaget i alt 0 karma
Sorter efter stemmer Sorter efter dato
... så vidt jeg har forstået så må den anden klasse (Altså den der implementere den abstracte klasse) ikke ændres fremover men kun udvides i en ny klasse der nedarver fra den - er det korrekt?

Korrekt. Men jeg tror du misforstår. Princippets formål er ikke at forbyde dig at ændre dine klasse, det er blot en ønsket effekt af det. Formålet er at du strukturerer dine klasser (og moduler), sådan at det ikke er nødvendigt at ændre i dine superklasser (hvilket er en dårlig ide siden det påvirker alle andre nedarvinger); i stedet når du skal tilføje ny funktionalitet kan du nedarve. På den måde ender du med en klasse der er lukket for ændringer, men åben for udvidelse (nedarving i dette tilfælde).

Se eventuelt dette eksempel, http://www.oodesign.com/open-close-principle.html , den (det første eksempel) opfylder ikke open-closed princippet. For at udvide funktionalitet med en ny figur, skal du ændre i superklassen du kan ikke blot nedarve, så GraphicEditor klassen er ikke lukket for ændringer, ej er den designet sådan at den er åben for udvidelse.

Hvis ovenstående er korrekt, må jeg så overhovedet foretage ændringer i det generelle interface? Ændringerne der jo vil slå igennem i den abstakte klasse også.


Hvis det kun er dig der roder med koden kan du gøre alt det du vil. Men har du tredje-parts bruger, eller andre udviklere som arbejder på andre moduler, bør man aldrig ændre et interface. Det gør at alle der bruger det direkte eller indirekte skal lave ændringer, specielt hvis det ikke blot er en omdøbning af en metode, open-closed princip eller ej.

Det er faktisk en af de originale årsager til princippet, hvis nogen ændrede i et interface, eller den synlige adfærd i en klasse, blev alle implementørerne påvirket. Specielt hvis det indebærede at tredjeparts brugere pludselig skulle rekompilere deres dll filer for at det igen virkede sammen med din dll fil f.eks.. Hvis man følger open-closed princippet er alt tredjepartsfunktionalitet lavet i deres egen klasser (open-delen), og du lader, efter offentligtgørelsen af dine klasse, være med ændre din base-klasse (closed-delen).


Bonus spørgsmål; Såfremt der skal en ny klasse til for hver ændring, hvad vil være mest hensigtsmæssigt i forhold til navngivning?

Hvad mener du bestemt når du siger for hver ændring? Hvis vi snakker om en RedColor klasse, og en BlueColor klasse, vil det være oplagt at generalise det til en Color klasse som tager et farve som argument i constructoren f.eks..

Snakker vi mere adfærdsspecifik kode kan adfærden bruges til at forme navnet. F.eks. en fjernbetjening hvor der bruges Command mønsteret, og alle klasser skal implementere metoden "Action", kan en klassen til at slukke navngives "TurnOffCommand". Knappen til at skrue op kan navngives "IncreaseVolumeCommand" osv..

Ellers må du lige give et konkret problem hvor det er svært med navnene.



Indlæg senest redigeret d. 08.12.2015 19:19 af Bruger #14645


Korrekt. Men jeg tror du misforstår. Princippets formål er ikke at forbyde dig at ændre dine klasse, det er blot en ønsket effekt af det. Formålet er at du strukturerer dine klasser (og moduler), sådan at det ikke er nødvendigt at ændre i dine superklasser (hvilket er en dårlig ide siden det påvirker alle andre nedarvinger); i stedet når du skal tilføje ny funktionalitet kan du nedarve. På den måde ender du med en klasse der er lukket for ændringer, men åben for udvidelse (nedarving i dette tilfælde).

Se eventuelt dette eksempel, http://www.oodesign.com/open-close-principle.html , den (det første eksempel) opfylder ikke open-closed princippet. For at udvide funktionalitet med en ny figur, skal du ændre i superklassen du kan ikke blot nedarve, så GraphicEditor klassen er ikke lukket for ændringer, ej er den designet sådan at den er åben for udvidelse.


Mange tak for forklaringen, jeg kan godt se at, jeg misforstod at, det skulle være den ønskede effekt! Jeg prøver mig lidt frem, men det giver god mening det du skriver.



Jeg har et interface, som bliver implementeret af en abstract klasse, hvor alle metoder er virtual (Jeg koder i C#)
Den klasse bliver så igen implementeret i en anden klasse.

Hvad er din bevæggrund for at have et interface, som bliver implementeret af en abstrakt klasse, for dernæst til sidst at blive implementeret af nogen underklasser?



Indlæg senest redigeret d. 09.12.2015 15:11 af Bruger #18836
Jeg sidder med et nyt hyggeprojekt, hvor jeg prøver at følge SOLID principperne.
I den forbindelse har jeg et spørgsmål angående Open/Closed pricippet.


Prøv evt. at kig på hvordan GoF Strategy Pattern fungerer. Selvom du ikke ligefrem vil benytte strategier, så viser det ganske fint, hvordan man kan implementere Open/Closed således, at en klasse sjældent/aldrig behøver at blive ændret for at tilføje ny funktionalitet. Der kan også nævnes GoF Template Pattern. Både Strategy Pattern og Template Pattern overholder i høj grad Open/Closed princippet.

Hvad er din bevæggrund for at have et interface, som bliver implementeret af en abstrakt klasse, for dernæst til sidst at blive implementeret af nogen underklasser?


Det kunne være, at den abstrakte klasse kun er én ud af flere, som implementerer interfacet. Og at denne indeholder funktionalitet der ønskes gentaget flere steder.





t