Hiërarchische ontbinding
Begin nooit meteen met het schrijven van lessen voor je toepassing. Eerst moet het ontworpen worden. Het ontwerp moet eindigen met een doordachte architectuur. En om deze architectuur te krijgen, moet je het systeem consequent ontleden.
Ontleding moet hiërarchisch worden uitgevoerd - eerst wordt het systeem verdeeld in grote functionele modules / subsystemen die de werking ervan in de meest algemene vorm beschrijven. Vervolgens worden de resulterende modules in meer detail geanalyseerd en onderverdeeld in submodules of objecten.
Voordat u objecten selecteert, verdeelt u het systeem in semantische basisblokken, tenminste mentaal. In kleine applicaties is dit meestal heel gemakkelijk te doen: een paar hiërarchieniveaus zijn voldoende, aangezien het systeem eerst wordt opgedeeld in subsystemen / pakketten en pakketten worden onderverdeeld in klassen.
![Hiërarchische ontbinding](https://cdn.codegym.cc/images/article/d5e9aa2b-5783-430f-b5b5-1832bc33c540/800.jpeg)
Dit idee is niet zo triviaal als het lijkt. Wat is bijvoorbeeld de essentie van zo'n algemeen "architectonisch patroon" als Model-View-Controller (MVC)?
Het gaat erom de presentatie te scheiden van de bedrijfslogica . Ten eerste is elke gebruikerstoepassing verdeeld in twee modules: de ene is verantwoordelijk voor het implementeren van de bedrijfslogica zelf (model) en de tweede is verantwoordelijk voor de interactie met de gebruiker (gebruikersinterface of weergave).
Dan blijkt dat de modules op de een of andere manier moeten communiceren, hiervoor voegen ze een controller toe, wiens taak het is om de interactie van de modules te beheren. Ook in de mobiele (klassieke) versie van MVC wordt het Observer-patroon eraan toegevoegd, zodat de View gebeurtenissen van het model kan ontvangen en de weergegeven gegevens in realtime kan wijzigen.
Typische modules van het hoogste niveau, verkregen als resultaat van de eerste verdeling van het systeem in de grootste componenten, zijn precies:
- Zakelijke logica;
- Gebruikersomgeving;
- Gegevensbestand;
- Berichtensysteem;
- Objectcontainer.
De eerste splitsing splitst meestal de hele applicatie op in 2-7 (maximaal 10 delen). Als we het in meer delen opsplitsen, zal er een wens zijn om ze te groeperen en krijgen we opnieuw 2-7 modules op het hoogste niveau.
Functionele ontleding
De indeling in modules/subsystemen kan het beste gebeuren op basis van de taken die het systeem oplost . De hoofdtaak is opgedeeld in de samenstellende deeltaken, die autonoom en onafhankelijk van elkaar kunnen worden opgelost/uitgevoerd.
Elke module zou verantwoordelijk moeten zijn voor het oplossen van een deeltaak en het uitvoeren van de overeenkomstige functie . Naast het functionele doel wordt de module ook gekenmerkt door een set gegevens die nodig zijn om zijn functie uit te voeren, namelijk:
Module = Functie + Gegevens die nodig zijn om het uit te voeren.
Als de ontbinding in modules correct gebeurt, zal de interactie met andere modules (verantwoordelijk voor andere functies) minimaal zijn. Het kan zijn, maar de afwezigheid ervan zou niet kritiek moeten zijn voor uw module.
Een module is geen willekeurig stukje code, maar een aparte functioneel zinvolle en complete programma-eenheid (subprogramma) die een oplossing biedt voor een bepaalde taak en idealiter zelfstandig of in een andere omgeving kan werken en hergebruikt kan worden. De module moet een soort 'integriteit zijn die in staat is tot relatieve onafhankelijkheid in gedrag en ontwikkeling'. (Christoffel Alexander)
Competente decompositie is dus in de eerste plaats gebaseerd op de analyse van de systeemfuncties en de gegevens die nodig zijn om deze functies uit te voeren. Functies zijn in dit geval geen klassenfuncties en modules, omdat het geen objecten zijn. Als je maar een paar lessen in een module hebt, dan heb je het overdreven.
Sterke en zwakke connectiviteit
Het is erg belangrijk om het niet te overdrijven met modularisatie. Als je een beginner een monolithische Spring-applicatie geeft en hem vraagt deze in modules op te splitsen, dan zal hij elke Spring Bean in een afzonderlijke module nemen en van mening zijn dat zijn werk is voltooid. Maar dat is het niet.
Het belangrijkste criterium voor de kwaliteit van de decompositie is hoe de modules gericht zijn op het oplossen van hun taken en onafhankelijk zijn.
Dit wordt gewoonlijk als volgt geformuleerd: "De als resultaat van decompositie verkregen modules dienen intern maximaal geconjugeerd te zijn (hoge interne cohesie) en minimaal met elkaar verbonden te zijn (lage externe koppeling)."
Hoge cohesie, hoge cohesie of "cohesie" binnen de module, geeft aan dat de module gericht is op het oplossen van één klein probleem en niet betrokken is bij het uitvoeren van heterogene functies of niet-gerelateerde verantwoordelijkheden.
Samenhang kenmerkt de mate waarin de taken die de module uitvoert met elkaar verband houden.
Een consequentie van High Cohesion is het Single Responsibility Principle - het eerste van de vijf SOLID-principes , volgens welke elk object/module slechts één verantwoordelijkheid mag hebben en er niet meer dan één reden mag zijn om het te wijzigen.
Laag Koppeling , losse koppeling, houdt in dat de modules waarin het systeem is opgedeeld, indien mogelijk onafhankelijk of losjes aan elkaar gekoppeld dienen te zijn. Ze moeten kunnen communiceren, maar tegelijkertijd zo weinig mogelijk van elkaar weten.
Niet elke module hoeft te weten hoe de andere module werkt, in welke taal hij is geschreven en hoe hij werkt. Om de interactie van dergelijke modules te organiseren, wordt vaak een bepaalde container gebruikt waarin deze modules worden geladen.
Als u met een goed ontwerp één module wijzigt, hoeft u andere niet te bewerken, anders zijn deze wijzigingen minimaal. Hoe losser de koppeling, hoe gemakkelijker het is om het programma te schrijven/begrijpen/uitbreiden/repareren.
Er wordt aangenomen dat goed ontworpen modules de volgende eigenschappen moeten hebben:
- Functionele integriteit en volledigheid - elke module implementeert één functie, maar implementeert deze goed en volledig, de module voert onafhankelijk een volledige reeks bewerkingen uit om zijn functie te implementeren.
- Eén invoer en één uitvoer - bij de invoer ontvangt de programmamodule een bepaalde set initiële gegevens, voert zinvolle verwerking uit en retourneert één set resultaatgegevens, dat wil zeggen dat het standaard IPO-principe is geïmplementeerd - invoer -\u003e proces -\u003e uitvoer.
- Logische onafhankelijkheid - het resultaat van het werk van de programmamodule hangt alleen af van de initiële gegevens, maar is niet afhankelijk van het werk van andere modules.
- Zwakke informatieverbindingen met andere modules - de uitwisseling van informatie tussen modules moet indien mogelijk tot een minimum worden beperkt.
Het is erg moeilijk voor een beginner om te begrijpen hoe de connectiviteit van modules nog meer kan worden verminderd. Deels komt deze kennis met ervaring, deels - na het lezen van slimme boeken. Maar het beste is om de architecturen van bestaande applicaties te analyseren.
Samenstelling in plaats van overerving
Competente decompositie is een soort kunst en een moeilijke taak voor de meeste programmeurs. Eenvoud is hier bedrieglijk en fouten zijn kostbaar.
![](https://cdn.codegym.cc/images/article/d7e785ed-e16d-4354-883c-0ad83327512a/512.jpeg)
Het komt voor dat dedicated modules sterk aan elkaar gekoppeld zijn en niet onafhankelijk ontwikkeld kunnen worden. Of het is niet duidelijk voor welke functie elk van hen verantwoordelijk is. Als u een soortgelijk probleem tegenkomt, is de partitionering in modules hoogstwaarschijnlijk niet correct uitgevoerd.
Het moet altijd duidelijk zijn welke rol elke module speelt . Het meest betrouwbare criterium dat de decompositie correct wordt uitgevoerd, is of de modules onafhankelijke en waardevolle subroutines zijn die geïsoleerd van de rest van de applicatie kunnen worden gebruikt (en dus opnieuw kunnen worden gebruikt).
Bij het ontleden van een systeem is het wenselijk om de kwaliteit ervan te controleren door uzelf de volgende vragen te stellen: "Welke taak voert elke module uit?", "Hoe gemakkelijk zijn de modules te testen?", "Is het mogelijk om de modules afzonderlijk te gebruiken of in een andere omgeving?" anderen beïnvloeden?"
Je moet proberen de modules zo autonoom mogelijk te houden . Zoals eerder vermeld, is dit een sleutelparameter voor een goede ontleding . Daarom moet het zo worden uitgevoerd dat de modules aanvankelijk zwak van elkaar afhankelijk zijn. Als het je is gelukt, dan ben je geweldig.
Zo niet, dan is ook hier niet alles verloren. Er zijn een aantal speciale technieken en patronen waarmee u de koppelingen tussen subsystemen verder kunt minimaliseren en verzwakken. In het geval van MVC is hiervoor bijvoorbeeld het Observer-patroon gebruikt, maar er zijn ook andere oplossingen mogelijk.
Er kan worden gezegd dat technieken voor ontkoppeling de belangrijkste "gereedschapskist van architecten" vormen. Het is alleen nodig om te begrijpen dat we het hebben over alle subsystemen en het is noodzakelijk om de verbinding op alle niveaus van de hiërarchie te verzwakken , dat wil zeggen niet alleen tussen klassen, maar ook tussen modules op elk hiërarchisch niveau.