
S.O.L.I.D: de eerste vijf principes van Object Oriented Design (OOD)
S.O.L.I.D is een acroniem voor de eerste vijf object-oriented design (OOD) principes van Robert C. Martin, of Uncle Bob
S.O.L.I.D. staat voor:
- Single responsibility principle
- Open closed principle
- Liskov substitution principle
- Interface segregation principle
- Dependency inversion principle
Om dit artikel niet te lang te en te ingewikkeld te maken gaan we alleen in op de volgende onderwerpen:
- Single responsibility principle
- Open closed principle
- Dependency inversion principle
Single responsibility principle
S.R.P. in het kort. Dit principe vertelt ons:
âA class should have one and only one reason to change, meaning that a class should have only one job.â
Oftewel, een class moet maar één doel hebben en daarmee dus maar ook één reden hebben om te worden aangepast.
Bovenstaande code bevat twee classes die allebei één doel hebben. Veel ontwikkelaars zullen de neiging hebben om deze code in dezelfde classe te plaatsen, maar dat is volgens het S.R.P. principe dus niet juist.
Open-Closed Principle
Dit principe staat voor:
âObjects or entities should be open for extension, but closed for modification.â
Simpel gezegd: een class moet makkelijk uit te breiden zijn, zonder de gehele classe aan te passen.
Voorbeeld
Voor dit voorbeeld maken we gebruik van een rectangle class. Logischerwijs heeft een rectangle een hoogte en een breedte:
Stel je voor dat je een collectie van rechthoeken hebt waarvan je de oppervlakte van wilt weten. Geen probleem dat kan met de volgende class:
Maar als je nu ook de oppervlakte wilt berekenen van een cirkel, met dezelfde AreaCalculator heb je een probleem, wat je als volgt op zou kunnen lossen:
Deze oplossing zal uiteraard gewoon werken, alleen als je van nog meer vormen zoals een driehoek wilt toevoegen moet je er weer een extra conditie worden toegevoegd. De class moet dus elke keer worden aangepast als er iets extraâs bijkomt. Nu is het in dit simpele voorbeeld geen probleem, maar in de echte wereld waar de code complex is, is dit wel een probleem.
De oplossing:
De oplossing is om een abstracte basis class te maken voor alle vormen met daarin een methode voor het berekenen van de oppervlakte.
De Rectangle en de Circle classes komen er dan als volgt uit te zien:
De areaCalculator ziet er dan als volgt uit:
In andere woorden: het is nu gesloten voor veranderingen door het te openen voor uitbreidingen.
Dependency Inversion principle
Dit principe vertelt ons:
âEntities must depend on abstractions not on concretions. It states that the high level module must not depend on the low level module, but they should depend on abstractions.â.
Dit klinkt misschien gek, maar is eenvoudig te begrijpen. Dit is het makkelijkste met een voorbeeld.
Voorbeeld
Je hebt misschien een bepaalde class die een wachtwoord reminder moet sturen. Hiervoor is een verbinding met de database nodig. Dit zou je op deze manier op kunnen lossen:
De DbConnection is een low level module en de PasswordReminder is een high level module. Volgens bovenstaande intentie van het principe klopt onze code dus niet.
Als je namelijk een wijziging wilt maken in de database verbinding moet dit overal worden aangepast. Daarnaast wordt ook het Open-Closed principe hiermee geschonden.
Oplossing
In bovestaande voorbeeld is moet het niet uit maken voor de PasswordReminder class welke database verbinding er wordt gebruikt.
Daarom plaatsen we de DbConnection in een interface.
De volledige implementatie ziet er dan als volgt uit:
Zoals je kunt zien in bovenstaande code zie je dat de high level en de low level module beide leunen op een abstractie.
Conclusie
Op het eerste oog lijken bovenstaande principes veel werk om te implementeren, maar op het lange termijn is je code eenvoudiger aan te passen, uit te breiden, testen en refactoren zonder problemen.