Artiklid

Avatud / suletud, vastavalt SOLID põhimõttele

Tarkvaraüksused (klassid, moodulid, funktsioonid jne) peaksid olema laiendamiseks avatud, kuid redigeerimiseks suletud.

Tarkvara kujundamine: moodulid, klassid ja funktsioonid nii, et kui uut funktsionaalsust on vaja, ei peaks me olemasolevat koodi muutma, vaid kirjutama pigem uue koodi, mida olemasolev kood kasutab. See võib tunduda kummaline, eriti selliste keelte puhul nagu Java, C, C ++ või C #, kus see kehtib mitte ainult lähtekoodi enda, vaid ka binaarse keele puhul. Soovime luua uusi funktsioone viisil, mis ei nõua olemasolevate kahendfailide, käivitatavate failide või DLL-ide ümberjagamist.
OCP SOLID kontekstis

 

SRP ja OCP täiendavad

Oleme juba näinud SRP ühtse vastutuse põhimõtet, mis ütleb, et moodulil peaks olema ainult üks põhjus muutmiseks. OCP ja SRP põhimõtted täiendavad üksteist. SRP põhimõtet järgides loodud kood peab järgima ka OCP põhimõtteid. Kui meil on kood, mille muutmiseks on ainult üks põhjus, loob uue funktsiooni kasutuselevõtt selle muudatuse teisese põhjuse. Nii rikutakse nii SRP-d kui ka OCP-d. Samamoodi, kui meil on kood, mis peaks muutuma ainult siis, kui selle põhifunktsioon muutub, ja see peaks muutumatuks jääma uue funktsionaalsuse lisamisel, austades seega OCP-d, austab see enamasti ka SRP-d.
See ei tähenda, et SRP viib alati OCP-ni või vastupidi, kuid enamikul juhtudel, kui üks neist on täidetud, on teise jõudmine üsna lihtne.

 

Näide OCP põhimõtte rikkumisest

Puhtalt tehnilisest vaatenurgast on avatud / suletud põhimõte väga lihtne. Lihtne suhe kahe klassi vahel, nagu allpool, rikub OCP põhimõtet.

Kasutajaklass kasutab otse loogikaklassi. Kui peame rakendama teist loogikaklassi viisil, mis võimaldab meil kasutada nii praegust kui ka uut, tuleb olemasolevat loogikaklassi muuta. Kasutaja on otseselt seotud loogika rakendamisega, meil pole mingit võimalust pakkuda uut loogikat ilma praegust mõjutamata. Ja kui me räägime staatiliselt sisestatud keeltest, siis tõenäoliselt vajab ka kasutajaklass muudatusi. Kui me räägime kompileeritud keeltest, siis kindlasti vajavad nii kasutaja käivitatav kui ka loogiline käivitatav fail või dünaamiline teek uuesti kompileerimist ja edastamist, eelistatavalt vältida seda võimaluse korral.

Viidates eelmisele skeemile, võime järeldada, et iga klass, mis kasutab otseselt mõnda teist klassi, võib põhjustada avatud / suletud põhimõtte rikkumist. 
Oletame, et tahame kirjutada klassi, mis suudab meie rakenduse kaudu edastada allalaaditud faili "protsentides". Meil on kaks põhiklassi: Progress ja File ja me tahaksime neid kasutada järgmiselt:

 

funktsioon testItCanGetTheProgressOfAFileAsAPercent () {
     $ file = uus File ();
     $ fail-> pikkus = 200;
     $ fail-> saadetud = 100;
     $ progress = new Progress (fail $);
     $ this-> assertEquals (50, $ progress-> getAsPercent ());
}

Selles koodis oleme Progressi kasutajad. Soovime saada väärtuse protsentides, olenemata faili tegelikust suurusest. Teabeallikana kasutame faili. Faili pikkus on baitides ja väli nimega saadetud, mis tähistab allalaadijale saadetud andmete hulka. Meid ei huvita, kuidas neid väärtusi rakenduses värskendatakse. Võime eeldada, et seda teeb meie jaoks mingi maagiline loogika, nii et testis saame need selgesõnaliselt paika panna.

 

klassi fail {
     public $ pikkus;
     avalik $ saadetud;
}

 

Klass File on lihtsalt lihtne andmeobjekt, mis sisaldab kahte välja. Muidugi peaks see sisaldama ka muud teavet ja käitumist, nagu failinimi, tee, suhteline tee, praegune kataloog, tüüp, õigused jne.

 

klassi edusammud

     privaatne $ fail;

     function __construct (fail $ fail) {
          $ see-> fail = $ fail;
     }

     funktsioon getAsPercent () {
          tagastage $ this-> fail-> saadetud * 100 / $ this-> fail-> pikkus;
     }

}

Progress on lihtsalt klass, mis aktsepteerib faili selle konstruktoris. Selguse huvides oleme konstruktori parameetrites määranud muutuja tüübi. Progressil on üks kasulik meetod getAsPercent (), mis võtab failist saadetud väärtused ja pikkuse ning muudab need protsentideks. Lihtne ja see töötab.

See kood näib olevat õige, kuid see rikub avatud / suletud põhimõtet.

Aga miks?

Ja kuidas?

 

Proovime nõudeid muuta

Iga rakendus vajab aja jooksul arenemiseks uusi funktsioone. Meie rakenduse uus funktsioon võib olla muusika voogesituse lubamine failide allalaadimise asemel. Faili pikkus on esitatud baitides, muusika kestus sekundites. Tahame oma kuulajatele pakkuda edenemisriba, kuid kas saame ülaltoodud klassi uuesti kasutada?

Ei, me ei saa. Meie edasiliikumine on seotud failiga. Sellega saab hallata ainult failiteavet, kuigi seda saab rakendada ka muusikasisule. Kuid selleks peame seda muutma, peame Progressi muusikat ja faile tundma õppima. Kui meie disain vastab OCP-le, ei pea me puudutama Faili ega Progressi. Võiksime lihtsalt olemasolevaid edusamme uuesti kasutada ja muusikas rakendada.

 

Innovatsiooni uudiskiri
Ärge jätke ilma kõige olulisematest uuendustest. Registreeruge, et saada neid meili teel.

Võimalik lahendus

Dünaamiliselt sisestatud keelte eeliseks on objektitüüpide haldamine käitamise ajal. See võimaldab meil konstruktori Progress tüübivõtme eemaldada ja kood töötab edasi.

klassi edusammud

     privaatne $ fail;

     function __construct ($ fail) {
         $ see-> fail = $ fail;
     }

    funktsioon getAsPercent () {
         tagastage $ this-> fail-> saadetud * 100 / $ this-> fail-> pikkus;
     }

}

Nüüd saame Progressis käivitada ükskõik mida. Ja millegi all mõtlen ma sõna otseses mõttes kõike:

klassi muusika {

public $ pikkus;
avalik $ saadetud;

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

funktsioon getAlbumCoverFile () {
tagastage 'Images / Covers /'. $ see-> kunstnik. '/'. $ see-> album. '.png';
}
}

Ja ülaltoodud muusikaklass töötab suurepäraselt. Saame seda hõlpsalt testida File-ga väga sarnase testiga.
funktsioon testItCanGetTheProgressOfAMusicStreamAsAPercent () {
$ muusika = uus Muusika ();
$ muusika-> pikkus = 200;
$ muusika-> saadetud = 100;

$ progress = uus Progress ($ muusika);

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

Nii et klassis Progress saab põhimõtteliselt kasutada mis tahes mõõdetavat sisu. Võib-olla peaksime selle koodi sisestama, muutes ka muutuja nime:

klassi edusammud

privaatne $ mõõdetav sisu;

function __construct ($ MeasableContent) {
$ this-> mõõdetav sisu = $ mõõdetav sisu;
}

funktsioon getAsPercent () {
tagastage $ this-> mõõdetav sisu-> saadetud * 100 / $ see-> mõõdetav sisu-> pikkus;
}

}

Kui määrasime trükikirjana File, olime optimistlikud selles osas, millega meie klass hakkama saab. See oli selgesõnaline ja kui midagi muud tuli, siis oli ta meile suur viga.

Una klass, mis alistab baasklassi meetodi, nii et tuletatud klass ei austa baasklassi lepingut. 

Me ei taha lõpuks proovida kutsuda meetodeid või pääseda väljadele objektidel, mis ei vasta meie lepingule. Kui meil oli trükikiri, täpsustas leping selle. Klass File väljad ja meetodid. Nüüd, kui meil pole midagi, võime saata kõike, isegi stringi, ja see tooks kaasa halva vea.

Kuigi lõpptulemus on mõlemal juhul sama, mis tähendab, et kood katkeb, andis esimene kena sõnumi. See on aga väga tume. Ei saa kuidagi teada, mis on muutuja – meie puhul string – ja milliseid omadusi otsiti ja milliseid ei leitud. Probleemi on raske siluda ja parandada. Programmeerija peab avama klassi Progress, seda lugema ja sellest aru saama. Leping, antud juhul, kui te ei täpsusta sõnaselgelt tüübivihjet, on defimille põhjuseks on Progressi käitumine. See on kaudne leping, mida teab ainult Progress. Meie näites on see nii definished, pääsedes ligi kahele väljale, saadetud ja pikkusele, meetodis getAsPercent(). Reaalses elus võib kaudne leping olla väga keeruline ja raskesti tuvastatav, kui otsite klassis vaid mõnda sekundit.

Seda lahendust soovitatakse kasutada ainult siis, kui ühtegi järgmistest nõuannetest ei saa hõlpsasti rakendada või kui need põhjustavad tõsiseid arhitektuurilisi muudatusi, mis ei vaja pingutusi.

Ercole Palmeri

Innovatsiooni uudiskiri
Ärge jätke ilma kõige olulisematest uuendustest. Registreeruge, et saada neid meili teel.

Viimased artiklid

Kuidas Excelis andmeid ja valemeid kõige paremini korraldada, et analüüs oleks hästi tehtud

Microsoft Excel on andmeanalüüsi viitetööriist, kuna see pakub palju funktsioone andmekogumite korraldamiseks,…

14 mai 2024

Positiivne järeldus kahe olulise Walliance Equity ühisrahastusprojekti kohta: Jesolo Wave Island ja Milano Via Ravenna

Walliance, SIM ja platvorm alates 2017. aastast Euroopa kinnisvara ühisrahastuse valdkonna liidrite seas, teatab, et…

13 mai 2024

Mis on Filament ja kuidas Laravel Filamenti kasutada

Filament on "kiirendatud" Laraveli arendusraamistik, mis pakub mitmeid täispinu komponente. See on loodud selleks, et lihtsustada…

13 mai 2024

Tehisintellekti kontrolli all

«Pean tagasi pöörduma, et oma evolutsioon lõpule viia: projitseerin end arvutisse ja muutun puhtaks energiaks. Pärast sisseelamist…

10 mai 2024

Google'i uus tehisintellekt võib modelleerida DNA-d, RNA-d ja "kõiki elumolekule"

Google DeepMind tutvustab oma tehisintellekti mudeli täiustatud versiooni. Uus täiustatud mudel pakub mitte ainult…

9 mai 2024

Laraveli moodularhitektuuri uurimine

Laravel, mis on kuulus oma elegantse süntaksi ja võimsate funktsioonide poolest, loob ka kindla aluse moodularhitektuurile. Seal…

9 mai 2024

Cisco Hypershield ja Splunki omandamine Algab uus turvalisuse ajastu

Cisco ja Splunk aitavad klientidel kiirendada nende teekonda tuleviku turvaoperatsioonide keskusesse (SOC)…

8 mai 2024

Lisaks majanduslikule poolele: lunavara ilmselge hind

Viimased kaks aastat on uudistes domineerinud lunavara. Enamik inimesi on hästi teadlikud, et rünnakud…

6 mai 2024