Artikler

Åpen / lukket, i henhold til SOLID-prinsippet

Programvareenheter (klasser, moduler, funksjoner osv.) Skal være åpne for utvidelse, men stengt for redigering.

Beregnet lesetid: 7 minutter

Å designe programvaren: moduler, klasser og funksjoner på en slik måte at når vi trenger ny funksjonalitet, bør vi ikke endre eksisterende kode, men heller skrive ny kode som skal brukes av eksisterende kode. Dette kan virke rart, spesielt med språk som Java, C, C ++ eller C # hvor det ikke bare gjelder kildekoden selv, men også binæren. Vi ønsker å lage nye funksjoner på måter som ikke krever omfordeling av eksisterende binære filer, kjørbare filer eller DLL-filer.
OCP i SOLID-sammenheng

SRP og OCP utfyllende

Vi har allerede sett SRP-prinsippet om enkeltansvar som sier at en modul bare skal ha en grunn til å endre. OCP- og SRP-prinsippene er komplementære. Koden utformet etter SRP-prinsippet vil også respektere OCP-prinsippene. Når vi har kode som bare har én grunn til å endre, vil innføring av en ny funksjon skape en sekundær årsak til den endringen. Så både SRP og OCP ville bli brutt. På samme måte, hvis vi har kode som bare skal endres når hovedfunksjonen endres og skal forbli uendret når ny funksjonalitet er lagt til, og dermed respektere OCP, vil den også respektere SRP.
Dette betyr ikke at SRP alltid fører til OCP eller omvendt, men hvis en av dem overholdes, er det ganske enkelt å oppnå det andre.

Eksempel på brudd på OCP-prinsippet

Rent teknisk sett er det åpne / lukkede prinsippet veldig enkelt. Et enkelt forhold mellom to klasser, som den nedenfor, bryter OCP-prinsippet.

Brukerklassen bruker Logic-klassen direkte. Hvis vi trenger å implementere en annen Logic-klasse på en måte som lar oss bruke både den nåværende og den nye, må den eksisterende Logic-klassen endres. Brukeren er direkte knyttet til implementeringen av logikken, det er ingen måte for oss å gi ny logikk uten å påvirke den nåværende. Og når vi snakker om statiske typede språk, vil brukerklassen sannsynligvis også kreve endringer. Hvis vi snakker om kompilerte språk, vil helt sikkert både kjørbar bruker og Logic kjørbar eller det dynamiske biblioteket kreve rekompilering og levering, helst å unngå når det er mulig.

Med henvisning til forrige opplegg kan vi utlede at enhver klasse som direkte bruker en annen klasse, kan føre til brudd på Open / Closed-prinsippet. 
La oss anta at vi ønsker å skrive en klasse som kan gi fremdriften "i prosent" av en nedlastet fil, gjennom applikasjonen vår. Vi vil ha to hovedklasser, en fremgang og en fil, og jeg antar at vi vil bruke dem som følger:

function testItCanGetTheProgressOfAFileAsAPercent() {
     $file = new File();
     $file->length = 200;
     $file->sent = 100;
     $progress = new Progress($file);
     $this->assertEquals(50, $progress->getAsPercent());
}

I denne koden er vi Progress-brukere. Vi ønsker å få en verdi i prosent, uavhengig av den faktiske filstørrelsen. Vi bruker File som en kilde til informasjon. En fil har en lengde i byte og et felt kalt sendt som representerer mengden data sendt til nedlasteren. Vi bryr oss ikke om hvordan disse verdiene oppdateres i applikasjonen. Vi kan anta at det er noen magisk logikk som gjør dette for oss, så i en test kan vi eksplisitt sette dem.

class File {
     public $length;
     public $sent;
}

Filklassen er bare et enkelt dataobjekt som inneholder de to feltene. Selvfølgelig bør den også inneholde annen informasjon og atferd, for eksempel filnavn, bane, relativ bane, gjeldende katalog, type, tillatelser og så videre.

class Progress {

     private $file;

     function __construct(File $file) {
          $this->file = $file;
     }

     function getAsPercent() {
          return $this->file->sent * 100 / $this->file->length;
     }

}

Fremgang er ganske enkelt en klasse som godtar en fil i konstruktøren. For klarhetens skyld har vi spesifisert variabeltypen i konstruktorparametrene. Det er en enkelt nyttig metode på Progress, getAsPercent (), som tar de sendte verdiene og lengden fra File og gjør dem til en prosentandel. Enkelt og det fungerer.

Denne koden ser ut til å være riktig, men den bryter med Open / Closed-prinsippet.

Men hvorfor?

Og hvordan?

La oss prøve å endre kravene

Hver applikasjon trenger nye funksjoner for å utvikle seg over tid. En ny funksjon for applikasjonen vår kan være å tillate streaming av musikk i stedet for bare å laste ned filer. Lengden på filen er representert i byte, hvor lenge musikken varer i sekunder. Vi ønsker å tilby en fremdriftslinje til lytterne våre, men kan vi bruke klassen som er skrevet ovenfor?

Nyhetsbrev for innovasjon
Ikke gå glipp av de viktigste nyhetene om innovasjon. Registrer deg for å motta dem på e-post.

Nei vi kan ikke. Vår progresjon er bundet til File. Den kan bare administrere filinformasjon, selv om den også kan brukes på musikkinnhold. Men for å gjøre det må vi endre det, vi må gjøre Progress kjent med musikken og filene. Hvis designet vårt overholdt OCP, trenger vi ikke å trykke på File eller Progress. Vi kan bare gjenbruke eksisterende fremgang og bruke den på musikk.

Mulig løsning

Dynamisk typte språk har fordelen av å administrere objekttyper i løpetid. Dette lar oss fjerne typehint fra Progress-konstruktøren, og koden vil fortsette å fungere.

class Progress {

     private $file;

     function __construct($file) {
         $this->file = $file;
     }

    function getAsPercent() {
         return $this->file->sent * 100 / $this->file->length;
     }

}

Vi kan nå lansere hva som helst på Progress. Og med noe, mener jeg bokstavelig talt hva som helst:

class Music {

     public $length;
     public $sent;

     public $artist;
     public $album;
     public $releaseDate;

     function getAlbumCoverFile() {
         return 'Images/Covers/' . $this->artist . '/' . $this->album . '.png';
     }
}

Og Musikk-klassen som den ovenfor vil fungere perfekt. Vi kan enkelt teste den med en test som ligner på File.

function testItCanGetTheProgressOfAMusicStreamAsAPercent() {

     $music = new Music();
     $music->length = 200;
     $music->sent = 100;

     $progress = new Progress($music);

     $this->assertEquals(50, $progress->getAsPercent());
}

Så i utgangspunktet kan ethvert målbart innhold brukes med Progress-klassen. Kanskje vi bør uttrykke det i kode ved å også endre variabelnavnet:

class Progress {

     private $measurableContent;

     function __construct($measurableContent) {
          $this->measurableContent = $measurableContent;
     }

     function getAsPercent() {
          return $this->measurableContent->sent * 100 / $this->measurableContent->length;
     }

}

Da vi spesifiserte File som typehint, var vi optimistiske med hensyn til hva klassen vår takler. Det var eksplisitt, og hvis noe annet kom, ville en stor feil fortelle oss.

Una klasse som overstyrer en metode for en basisklasse slik at baseklassekontrakten ikke blir respektert av den avledede klassen. 

Vi vil ikke ende opp med å prøve å ringe metoder eller få tilgang til felt på objekter som ikke er i samsvar med kontrakten vår. Da vi hadde en typetips, ble kontrakten spesifisert av den. Feltene og metodene i filklassen. Nå som vi ikke har noe, kan vi sende noe, til og med en streng, og det vil føre til en feil.

Mens sluttresultatet er det samme i begge tilfeller, noe som betyr at koden går i stykker, ga førstnevnte en hyggelig melding. Dette er imidlertid veldig mørkt. Det er ingen måte å vite hva variabelen er – en streng i vårt tilfelle – og hvilke egenskaper som ble søkt etter og ikke funnet. Det er vanskelig å feilsøke og fikse problemet. En programmerer må åpne Progress-klassen, lese og forstå den. Kontrakten, i dette tilfellet, når du ikke eksplisitt spesifiserer typehintet, er defiavsluttet av fremdriftens oppførsel. Det er en underforstått kontrakt kun kjent for Progress. I vårt eksempel er det det defiavsluttes ved å få tilgang til de to feltene, sendt og lengde, i getAsPercent()-metoden. I det virkelige liv kan den underforståtte kontrakten være svært kompleks og vanskelig å oppdage ved bare å se etter noen få sekunder i timen.

Denne løsningen anbefales bare hvis ingen av de andre tipsene nedenfor lett kan implementeres, eller hvis de vil påføre alvorlige arkitektoniske endringer som ikke garanterer innsatsen.

Continua leggendo il terzo principio della sostituzione di Liskow —>

Relaterte lesninger

Ercole Palmeri

Nyhetsbrev for innovasjon
Ikke gå glipp av de viktigste nyhetene om innovasjon. Registrer deg for å motta dem på e-post.

Siste artikler

De fire pilarene for bærekraft

Begrepet bærekraft er nå mye brukt for å indikere programmer, initiativer og handlinger som tar sikte på å bevare en bestemt ressurs...

15 mai 2024

Hvordan konsolidere data i Excel

Enhver virksomhet produserer mye data, selv i forskjellige former. Skriv inn disse dataene manuelt fra et Excel-ark for å...

14 mai 2024

Cisco Talos kvartalsvise analyser: bedrifts-e-poster målrettet av kriminelle Produksjon, utdanning og helsevesen er de mest berørte sektorene

Kompromisset med bedrifts-e-poster økte mer enn det dobbelte i de tre første månedene av 2024 sammenlignet med siste kvartal av...

14 mai 2024

Interface segregation principle (ISP), fjerde SOLID-prinsipp

Prinsippet for grensesnittsegregering er ett av de fem SOLID prinsippene for objektorientert design. En klasse skal ha...

14 mai 2024

Hvordan organisere data og formler best i Excel, for en godt utført analyse

Microsoft Excel er referanseverktøyet for dataanalyse, fordi det tilbyr mange funksjoner for å organisere datasett,...

14 mai 2024

Positiv konklusjon for to viktige Walliance Equity Crowdfunding-prosjekter: Jesolo Wave Island og Milano Via Ravenna

Walliance, SIM og plattform blant de ledende i Europa innen eiendoms Crowdfunding siden 2017, kunngjør fullføringen...

13 mai 2024

Hva er Filament og hvordan du bruker Laravel Filament

Filament er et "akselerert" Laravel-utviklingsrammeverk, som gir flere fullstack-komponenter. Den er designet for å forenkle prosessen med...

13 mai 2024

Under kontroll av kunstig intelligens

«Jeg må tilbake for å fullføre utviklingen min: Jeg vil projisere meg selv inne i datamaskinen og bli ren energi. En gang bosatt seg i…

10 mai 2024

Les Innovasjon på ditt språk

Nyhetsbrev for innovasjon
Ikke gå glipp av de viktigste nyhetene om innovasjon. Registrer deg for å motta dem på e-post.

Følg oss