Funktsionaalne vs objektorienteeritud programmeerimine

Kuule poisid, vabandan viivituste pärast artiklite vahel. Ma räägin selles artiklis erinevusest FP (funktsionaalne programmeerimine) ja OOP (objektorienteeritud programmeerimine) ning sellest, millal on kõige parem neid kasutada.

Mida iganes saate teha ühe stiiliga, enamasti saate seda teha ka teise stiiliga. Kuid sõltuvalt probleemist, mida proovite lahendada, võib üks olla parem kui teine. Stiilid ei piira seda, milliseid programme te kirjutate, vaid see, kuidas te neid kirjutate. Nagu öeldud, pole ükski stiil alati parim. Parim on teada mõlemat, nii et saate kõige paremini iga olukorraga hõlpsalt hakkama saada. Vaatame siis järele!

Objektorienteeritud programmeerimine

See on kõige tuntum paradigma. Nagu nimigi ütleb, on selle kõige keskmes objekt. Objektid sisaldavad nii andmeid kui ka nende andmetega töötavat funktsionaalsust. Parim oli seda kirjeldada kui kasutada auto analoogiat.

Abstraktsioon:
Te ei saa autot ühe korraga ehitada. Peate selle väiksemateks tükkideks jagama. Mitte nii väike, et see oleks võimalikult väike detail. Kuid mitte nii suur, et see muutuks haldamiseks liiga suureks. Põhimõtteliselt jagate keeruka objekti väiksemateks komponentideks.

Kapseldamine:
Kui olete auto osadeks jaotanud. Peate mõtlema nende osade omadustele. Näiteks: raadius ja laius ning rehvi kasutamine. Samas mõttes hakkate oma auto ehitama, pannes kõik tükid kokku: objekti kompositsioon. Kapseldamine on põhimõtteliselt andmete ja funktsioonide rühmitamine, et neid andmeid kasutada. See muudab teie koodi modulaarsemaks.

Pärand:
Rehve on palju erinevaid. Talverehvid, talverehvid, suverehvid jne. Neil kõigil on sarnased omadused ja teatud erinevused. Te ei tahaks iga rehvi jaoks eraldi klassi kirjutada. Kõige parem on luua mall, mis sisaldab ühiseid funktsioone, ja seejärel luua spetsiaalsed klassid, mis sisaldavad spetsialiseeritud koodi. Põhimõtteliselt olete spetsiaalsed rehvid, mis pärivad vanematelt ühised omadused: rehv. See muudab teie koodi taaskasutatavaks.

Polümorfism:
See on viimane osa. Autot juhtides ei pea te teadma, kuidas kõik töötab. Autoga suhtlemiseks kasutate gaasipedaali, rooliratast ja käiguvahetust. Teil on programmiga suhtlemiseks üks või mitu liidest ja teil pole aimugi koodi sisemisest toimimisest. See tagab, et keegi muu kui teie, looja, ei saa teie koodi segamini ajada.

Funktsionaalne programmeerimine

Funktsionaalse programmeerimise võti on nimes: funktsioonid. FP on seotud muutumatuse ja funktsioonide, mitte objektide komponeerimisega. Lähme üle põhijooned tõesti kiiresti:

Funktsioonid on esmaklassilised. Neid saab mööda lasta, dünaamiliselt luua, salvestada andmestruktuuridesse ja töödelda nagu iga teist esmaklassilist objekti.

Kasutage puhtaid funktsioone. Puhas funktsioon on funktsioon, millel pole kõrvaltoimeid. Puhtfunktsioonidega programmeerides märkate modulaarsuse suurenemist, mis muudab koodi testimise, taaskasutamise, paralleelistamise, üldistamise ja põhjendamise lihtsamaks.

Funktsioone saab koostada. See on umbes nagu kapseldamine OOP-i. Suuremate funktsioonide loomiseks võite ühendada väiksemaid funktsioone. Pidage meeles, et funktsioonid on esmaklassilised.

Lausetele eelistatakse avaldisi. Väljendite saagise väärtused. Avaldused ei ole ja on olemas selleks, et aidata teil programmi voogu kontrollida.

Andmed on muutumatud. Andmestruktuuri muutmise asemel luuakse tõhusalt uus.

Andmeid muudetakse, neid ei muudeta. Kuna andmed on muutumatud, tuleb neid muuta. Niisiis, kui funktsioonile andmestruktuuri edastate, tuleb välja uus ja sisestatud jäetakse muutmata.

Üldine jutt on siin see, et kõrvaltoimeid pole. Aga mida see tähendab? Kuidas saate kirjutada, millel pole kõrvaltoimeid?

Kõrvaltoimete puudumine tähendab, et kood on kodakondsuseta. Programmi täitmisele ei ole muud mõju, kui selle sisenditele vastava tulemuse arvutamine. See on tingitud referentiaalse läbipaistvuse ideest. Lause on võrdlemisi läbipaistev, kui kõigi programmide korral saab kõik avaldise esinemised programmis asendada avaldise hindamise tulemusega, ilma et see mõjutaks programmi jälgitavat käitumist.

Näiteks: 1 + 2 võrdub alati 3. Selles mõttes on see puhas funktsioon, kuna väljund ei muutu antud sisendite korral kunagi. Nii et kõikjal, kus näete 1 + 2, saate selle lihtsalt asendada 3-ga ega näe programmi üldisel täitmisel kahjulikku mõju.

Soovituslik läbipaistvus võimaldab teil kasutada asendusmudelit. Võite mõelda väljenditele, nagu teeksite seda algebras. Suure võrrandi saate lahendada, asendades muutujad nende väärtustega, ja redigeerida selle kõige lihtsamale kujule. Te asendate võrdsed võrdsetega.

Nagu paremal näete, on x võrdluslikult läbipaistev. Pole tähtis, mitu korda te pöördumist või mõnda muud meetodit sellel helistate, on väljundväärtus alati sama. Puuduvad kõrvaltoimed. Nagu näiteks, saate x asendada selle tegeliku väärtusega ja saada ikkagi sama väljund. See on suurepärane, kui kirjutate koodi, mis peab töötama samaaegselt; te ei pea muretsema probleemide põhjustavate kõrvaltoimete pärast. Vaatame nüüd mõnda koodi koos kõrvaltoimetega.

Nagu näete, on StringBuilderi pöördfunktsioon puhas, kuid funktsioon append mitte. Iga kord, kui helistate, lisandub väljundi väärtus. See tähendab, et see ei ole võrdlemisi läbipaistev. Samaaegse programmi puhul võib see olla hukatuslik. Ärge muretsege, iga funktsioon koos kõrvaltoimetega võib jagada põhifunktsiooniks puhtaks ja üheks või mitmeks kõrvaltoimetega funktsiooniks.

Vaatame ülaltoodud näite koodi üle. Lõime funktsiooni deklareerida võitja, mis prindib kõige suurema punktisumma saanud mängija. Lihtne, eks? Mis oleks siis, kui tahaksime leida loendist või muust andmestruktuurist kõige suurema skooriga mängija? Mis oleks, kui me tahaksime osa koodist uuesti kasutada? Seda ei saa deklareeriWinneri esimese määratlusega täpselt teha.

Kuid kui jagada funktsioon puhtaks ja kõrvalmõjuga funktsiooniks. Me saame täpselt seda teha. Nagu näete, võime mängijate nimekirja läbi vaadata ja leida väga hõlpsalt kõrgeima punktisumma saanud mängija. See muutis ka meie koodi modulaarsemaks ja võimaldab meil funktsioone komponeerida.

Kohustuslik programmeerimine

Asi on lihtsalt programmeerimises avaldustega, mis muudavad programmi olekut. Oleme seda seni teinud koos OOP ja FP-ga. Laiendusena saate vajadusel segada FP ja OOP printsiipe. Need ei ole üksteist välistavad. Need on lihtsalt võimalused teatud probleemide optimaalseks lahendamiseks.

Näiteks: Java on klassikaline OOP-keel. Kuid nagu Java 8, on see muutunud funktsionaalsemaks, toetades lambda funktsioone. See pole küll täiesti funktsionaalne, kuid on sinna jõudmas.

Kasutage juhtumeid

FP puhul tuleb meeles pidada, et konkreetse sisendi korral on väljund alati sama ja sisend on alati muutumatu. Riigimuutusi pole. Nii et kui teil on vaja kirjutada lõime turvalist koodi, minge koos FP-ga.

OOP-i korral on oleku muutused normiks. Konkreetne sisend ei anna alati sama väljundit. Näiteks: mõelge otsingumootorile. Google ei taga alati sama otsinguklahvi korral samu tulemusi. See läheb vastu raamprogrammi direktoritele. Seega kasutage sel juhul OOP-i.

On rohkem olukordi, kus üks võib olla parem kui teine. Mälu kasutamine kipub OOP-is olema suurem, kuna kõik on objekt. FP peab iga kord, kui lisate uue elemendi, looma muutumatu andmestruktuuri uue koopia. Igal ühel on oma puudused.

Loodetavasti kirjeldas see nende kahe erinevust päris hästi. Millalgi varsti teen kande FP kujundusmustrite kohta. Ilmselt erinevad nad OOP omast. Seega on kindlasti oluline neid teada. Niisiis, olge valvel!

Kuidas FP ja OOP mind tunnevad.

Redigeeri

Tahaksin rõhutada mõnda asja:

Java ei ole täielikult OOP-keel. Sellel on primitiivsed ja staatilised liikmed, millest kumbki pole objekt. Scala on aga täiesti OOP-keel. Muidugi, võite kirjutada programme, mis sisaldavad Scalas FP ja OOP segu. Kuid Scalas on kõik objekt, isegi funktsioonid.

Miks valida see Java kaudu? Noh, Scala toetab kõiki FP-kontseptsioone, samas kui Java toetab ainult mõnda. See annab teile juurdepääsu paljudele võimsatele konstruktsioonidele, nagu mustri sobitamine jne. Teil on juurdepääs igale Java-le saadaval olevale teegile. Lõpuks töötab see JVM-il. See ei pruugi töötada sama kiiresti kui Java-kood, kuid kogu koormuse funktsionaalsuse jaoks saate kaubelda mõne mikrosekundi jooksul.

Kasutusjuhtumite osas lubage mul laiendada seda, mida ma juba ütlesin.

Kui peate kasutajaliidese ehitama, lähete ilmselt koos OOP-ga. Kõik selles olukorras on objekt.

Kui teil on palju erinevaid seotud andmetüüpe, mis jagavad funktsionaalsust ja plaanite tulevikus rohkem luua, peate tõenäoliselt kasutama pärandit. See võimaldab teil luua moodul- ja korduvkasutatava koodi. Minge koos OOP-ga.

Kui teil on ainult mõned andmetüübid, kuid nende teostamiseks on palju toiminguid ja tõenäoliselt ei lisata tulevikus uusi tüüpe, pole teil vaja pärandit. Minge koos FP-ga.

Kui konkreetset toimingut saab modelleerida nagu matemaatikaoperatsiooni, minge FP-ga. See võib tunduda segane, nii et laiendan seda. Oletagem, et soovite kirjutada programmi, mis liidab asjad kokku. Saate seda teha OOP-iga, kuid seda on FP-s palju lihtsam teha. Objekti piltide tegemine võtab aega ja ruumi. Miks selle kõigega vaeva näha?

FP on üldiselt suurepärane modelleerimisel, mis näib järgivat matemaatilist mustrit (nt: rekursiivsed meetodid). Kui saate programmi matemaatilise tõestusena modelleerida, minge koos FP-ga. See on ausalt parim nõuanne, mida ma teile anda saan.

Kumbki neist paradigmadest ei ole teineteist välistavad. Võite kirjutada paremaid programme, kui kasutate nende kahe kombinatsiooni. Peate lihtsalt teadma, millal seda kasutada. Minge katsetama!