Hierarkisk dekomponering
Du bør aldri begynne å skrive klasser for søknaden din med en gang. Først må den designes. Designet skal avsluttes med en gjennomtenkt arkitektur. Og for å få denne arkitekturen, må du konsekvent dekomponere systemet.
Dekomponering må utføres hierarkisk - først er systemet delt inn i store funksjonelle moduler / undersystemer som beskriver driften i den mest generelle formen. Deretter blir de resulterende modulene analysert mer detaljert og delt inn i undermoduler eller objekter.
Før du velger objekter, del systemet inn i grunnleggende semantiske blokker, i det minste mentalt. I små applikasjoner er dette vanligvis veldig enkelt å gjøre: et par nivåer av hierarki er nok, siden systemet først er delt inn i undersystemer / pakker, og pakker er delt inn i klasser.
![Hierarkisk dekomponering](https://cdn.codegym.cc/images/article/d5e9aa2b-5783-430f-b5b5-1832bc33c540/800.jpeg)
Denne ideen er ikke så triviell som den virker. Hva er for eksempel essensen av et så vanlig "arkitektonisk mønster" som Model-View-Controller (MVC)?
Det handler om å skille presentasjonen fra forretningslogikken . For det første er enhver brukerapplikasjon delt inn i to moduler - en er ansvarlig for å implementere selve forretningslogikken (Model), og den andre er ansvarlig for å samhandle med brukeren (brukergrensesnitt eller visning).
Da viser det seg at modulene på en eller annen måte må samhandle, for dette legger de til en Controller, som har som oppgave å administrere interaksjonen mellom modulene. Også i den mobile (klassiske) versjonen av MVC er Observer-mønsteret lagt til det slik at View kan motta hendelser fra modellen og endre de viste dataene i sanntid.
Typiske toppnivåmoduler, oppnådd som et resultat av den første inndelingen av systemet i de største komponentene, er nettopp:
- forretningslogikk;
- Brukergrensesnitt;
- Database;
- meldingssystem;
- Objektbeholder.
Den første delingen deler vanligvis hele applikasjonen i 2-7 (maksimalt 10 deler). Bryter vi det ned i flere deler, så vil det være et ønske om å gruppere dem, og vi får igjen 2-7 toppnivåmoduler.
Funksjonell dekomponering
Inndelingen i moduler/delsystemer gjøres best ut fra oppgavene som systemet løser . Hovedoppgaven er delt inn i sine konstituerende deloppgaver, som kan løses/utføres autonomt, uavhengig av hverandre.
Hver modul bør være ansvarlig for å løse en deloppgave og utføre den tilsvarende funksjonen . I tillegg til det funksjonelle formålet er modulen også preget av et sett med data som er nødvendig for at den skal utføre sin funksjon, det vil si:
Modul = Funksjon + Data som trengs for å utføre den.
Hvis dekomponeringen til moduler gjøres riktig, vil interaksjonen med andre moduler (ansvarlig for andre funksjoner) være minimal. Det kan være det, men fraværet bør ikke være kritisk for modulen din.
En modul er ikke en vilkårlig kodebit, men en egen funksjonelt meningsfull og komplett programenhet (underprogram) som gir en løsning på en bestemt oppgave og ideelt sett kan arbeide selvstendig eller i et annet miljø og gjenbrukes. Modulen skal være en slags "integritet som er i stand til relativ uavhengighet i atferd og utvikling." (Christopher Alexander)
Derfor er kompetent dekomponering først og fremst basert på analysen av systemfunksjonene og dataene som er nødvendige for å utføre disse funksjonene. Funksjoner i dette tilfellet er ikke klassefunksjoner og moduler, fordi de ikke er objekter. Hvis du bare har et par klasser i en modul, har du overdrevet det.
Sterk og svak tilkobling
Det er veldig viktig å ikke overdrive det med modularisering. Hvis du gir en nybegynner en monolitisk Spring-applikasjon og ber ham dele den opp i moduler, vil han ta ut hver Spring Bean i en separat modul og vurdere at arbeidet hans er ferdig. Men det er det ikke.
Hovedkriteriet for kvaliteten på dekomponeringen er hvordan modulene er fokusert på å løse sine oppgaver og er uavhengige.
Dette er vanligvis formulert som følger: "Modulene oppnådd som et resultat av dekomponering bør være maksimalt konjugert internt (høy intern kohesjon) og minimalt sammenkoblet med hverandre (lav ekstern kobling)."
Høy kohesjon, høy kohesjon eller "cohesion" innenfor modulen, indikerer at modulen er fokusert på å løse ett smalt problem, og ikke er engasjert i å utføre heterogene funksjoner eller ikke-relaterte ansvar.
Samhold karakteriserer i hvilken grad oppgavene som utføres av modulen er relatert til hverandre.
En konsekvens av High Cohesion er Single Responsibility Principle - det første av de fem SOLID-prinsippene , ifølge hvilket ethvert objekt/modul kun skal ha ett ansvar og det ikke bør være mer enn én grunn til å endre det.
Lav kobling , løs kobling, betyr at modulene som systemet er delt inn i, om mulig skal være uavhengige eller løst koblet til hverandre. De skal kunne samhandle, men samtidig vite minst mulig om hverandre.
Hver modul trenger ikke å vite hvordan den andre modulen fungerer, hvilket språk den er skrevet på og hvordan den fungerer. Ofte, for å organisere samspillet mellom slike moduler, brukes en viss beholder som disse modulene lastes inn i.
Med riktig design, hvis du endrer en modul, trenger du ikke å redigere andre, eller disse endringene vil være minimale. Jo løsere koblingen er, jo lettere er det å skrive/forstå/utvide/reparere programmet.
Det antas at godt utformede moduler bør ha følgende egenskaper:
- Funksjonell integritet og fullstendighet - hver modul implementerer en funksjon, men implementerer den godt og fullstendig, modulen utfører uavhengig et komplett sett med operasjoner for å implementere funksjonen sin.
- En inngang og en utgang - ved inngangen mottar programmodulen et visst sett med innledende data, utfører meningsfull behandling og returnerer ett sett med resultatdata, det vil si at standard IPO-prinsippet er implementert - input -\u003e prosess -\u003e produksjon.
- Logisk uavhengighet - resultatet av arbeidet til programmodulen avhenger bare av de første dataene, men avhenger ikke av arbeidet til andre moduler.
- Svake informasjonskoblinger med andre moduler - informasjonsutveksling mellom moduler bør minimeres om mulig.
Det er veldig vanskelig for en nybegynner å forstå hvordan man kan redusere tilkoblingen til moduler enda mer. Dels kommer denne kunnskapen med erfaring, dels – etter å ha lest smarte bøker. Men det er best å analysere arkitekturen til eksisterende applikasjoner.
Sammensetning i stedet for arv
Kompetent dekomponering er en slags kunst og en vanskelig oppgave for de fleste programmerere. Enkelhet er villedende her, og feil er kostbare.
![](https://cdn.codegym.cc/images/article/d7e785ed-e16d-4354-883c-0ad83327512a/512.jpeg)
Det hender at dedikerte moduler er sterkt koblet med hverandre og ikke kan utvikles uavhengig. Eller det er ikke klart hvilken funksjon hver av dem er ansvarlig for. Hvis du støter på et lignende problem, er det mest sannsynlig at partisjoneringen i moduler ble gjort feil.
Det skal alltid være klart hvilken rolle hver modul spiller . Det mest pålitelige kriteriet for at dekomponeringen gjøres riktig er om modulene er uavhengige og verdifulle subrutiner som kan brukes isolert fra resten av applikasjonen (og derfor kan gjenbrukes).
Når du dekomponerer et system, er det ønskelig å sjekke kvaliteten ved å stille deg selv spørsmålene: "Hvilken oppgave utfører hver modul?", "Hvor enkle er modulene å teste?", "Er det mulig å bruke modulene alene. eller i et annet miljø?" påvirke andre?"
Du må prøve å holde modulene så autonome som mulig . Som nevnt tidligere er dette en nøkkelparameter for riktig nedbrytning . Derfor må det utføres på en slik måte at modulene i utgangspunktet er svakt avhengige av hverandre. Hvis du lyktes, så er du stor.
Hvis ikke, så er ikke alt tapt her heller. Det finnes en rekke spesielle teknikker og mønstre som lar deg minimere og svekke koblingene mellom delsystemer ytterligere. For eksempel, i tilfellet med MVC, ble Observer-mønsteret brukt til dette formålet, men andre løsninger er mulige.
Det kan sies at teknikker for frakobling utgjør hoved "arkitektens verktøykasse". Det er bare nødvendig å forstå at vi snakker om alle undersystemer, og det er nødvendig å svekke forbindelsen på alle nivåer i hierarkiet , det vil si ikke bare mellom klasser, men også mellom moduler på hvert hierarkisk nivå.