Să mergem Programare orientată pe obiecte în Golang

Du-te este un amestec ciudat de idei vechi și noi. Ea are o abordare foarte răcoritoare în care nu se teme să arunce de la capăt noțiunile stabilite de "cum să facă lucrurile". Mulți oameni nu sunt siguri dacă Go este un limbaj orientat pe obiecte. Lasă-mă să pun asta în odihnă chiar acum. Este! 

În acest tutorial veți afla despre toate intricaciile designului orientat pe obiecte în Go, despre modul în care pillurile de programare orientate pe obiecte, cum ar fi încapsularea, moștenirea și polimorfismul sunt exprimate în Go, și cum Go se compară cu alte limbi.

Go este un limbaj de programare incredibil de puternic, învățați totul, de la scrierea de utilități simple la construirea de servere web scalabile și flexibile în întregime.

Filosofia Go Design

Rădăcinile lui Go se bazează pe C și, în general, pe familia Algol. Ken Thompson a spus cu jumătate de glumă că Rob Pike, Robert Granger și el însuși s-au adunat și au decis că urăsc C ++. Fie că este o glumă sau nu, Go este foarte diferită de C ++. Mai multe despre asta mai târziu. Du-te este despre simplitatea finală. Acest lucru este explicat în detaliu de Rob Pike în Less este exponențial mai mult.

Du-te în comparație cu alte limbi

Go nu are clase, obiecte, excepții și șabloane. Ea are colectare de gunoi și încorporat în concurrency. Cea mai frapantă omisiune în ceea ce privește orientarea obiectului este că nu există o ierarhie de tip în Go. Acest lucru este în contrast cu cele mai multe limbi orientate pe obiecte, cum ar fi C ++, Java, C #, Scala și chiar limbi dinamice precum Python și Ruby.

Accesați funcțiile de limbă orientate pe obiecte

Go nu are clase, dar are tipuri. În special, ea a structurat. Structurile sunt tipuri definite de utilizator. Tipurile de structuri (cu metode) servesc scopuri similare unor clase în alte limbi.

structs

Un struct definește starea. Aici este o creatură structură. Are un câmp Nume și un steag boolean numit Real, care ne spune dacă este o creatură reală sau o creatură imaginară. Structurile dețin doar stat și nici un comportament.

tip Creature struct Nume șir Real bool 

metode

Metodele sunt funcții care funcționează pe anumite tipuri. Ei au o clauză de receptor care mandatează ce tip de operațiune. Aici este Dump () metoda care opereaza pe creatura isi schita si imprima starea:

func (c Creature) Dump () fmt.Printf ("Nume: '% s', Real:% t \ n", c.Numele, c.Real)

Aceasta este o sintaxă neobișnuită, dar este foarte explicită și clară (spre deosebire de "sinele" implicit "de acest" sau de "sinele" confuz al lui Python).

încorporarea

Puteți încorpora tipuri anonime în interiorul celuilalt. Dacă încorporați un struct fără nume, structura încorporată oferă structura (și metodele) sale direct structurii de încorporare. De exemplu, FlyingCreature are un nume fără nume Creatură struct încorporat în el, ceea ce înseamnă a FlyingCreature este a Creatură.

tip FlyingCreature struct Creature WingSpan int

Acum, dacă aveți o instanță a unui FlyingCreature, puteți accesa atributele Nume și Real direct.

dragon: = & FlyingCreature Creature "Dragon", false,, 15, fmt.Println (dragon.Name) fmt.Println (dragon.Real) fmt.Println (dragon.WingSpan)

interfeţe

Interfețele sunt semnul distinctiv al suportului Go orientat pe obiect. Interfețele sunt tipuri care declară seturi de metode. În mod similar cu interfețele în alte limbi, acestea nu au nicio implementare. 

Obiectele care implementează toate metodele de interfață implementează automat interfața. Nu există nici un cuvânt cheie cu moștenire sau subclasare sau "implementează". În următorul fragment de cod, tastați Foo implementează interfața Fooer (prin convenție, numele interfețelor Go se termină cu "er").

(Foo1)) Foo1 () Foo2 () Foo3 () tip Foo struct  func (f Foo) Foo1 () fmt.Println .Println ("Foo2 () aici") func (f Foo) Foo3 () fmt.Println ("Foo3 () aici")

Obiect-Oriented Design: Calea de Go

Să vedem cum Go măsoară împotriva stâlpilor programării orientate obiect: încapsulare, moștenire și polimorfism. Acestea sunt caracteristicile limbajelor de programare bazate pe clasă, care sunt cele mai populare limbi de programare orientate spre obiect.

În esență, obiectele sunt construcții de limbaj care au stat și comportament care operează asupra statului și îl expun selectiv în alte părți ale programului. 

încapsularea

Du-te încapsulează lucrurile la nivelul pachetului. Numele care încep cu o literă mică sunt vizibile numai în acel pachet. Puteți ascunde orice într-un pachet privat și puteți expune doar anumite tipuri, interfețe și funcții din fabrică. 

De exemplu, aici pentru a ascunde foo tastați deasupra și expuneți doar interfața pe care ați putea să o redenumiți cu litere mici foo și să ofere o NewFoo ()funcția care returnează interfața publică Fooer:

() Foo1 () fmt.Println ("Foo1 () aici") func (f foo) Foo2 () fmt.Println fooo) Foo3 () fmt.Println ("Foo3 () aici") func NewFoo () Fooer return & Foo 

Apoi codul dintr-un alt pachet poate folosi NewFoo () și obțineți acces la un Fooer interfață implementată de sistemul intern foo tip:

f: = NewFoo () f.Foo1 () f.Foo2 () f.Foo3 ()

Moştenire

Moștenirea sau subclasarea a fost întotdeauna o problemă controversată. Există multe probleme cu moștenirea implementării (spre deosebire de moștenirea interfeței). Moștenirea multiplă implementată de C ++ și Python și alte limbi suferă de diamantul mortal al problemei morții, dar nici măcar moștenirea nu este un picnic cu problema fragilă de clasă de bază. 

Limbile moderne și gândirea orientată spre obiect favorizează acum compoziția asupra moștenirii. Du-te ia în inimă și nu are nici o ierarhie de tip. Acesta vă permite să împărtășiți detaliile implementării prin compoziție. Dar Du-te, într-o răsucire foarte ciudată (probabil pornită din preocupări pragmatice), permite compoziția anonimă prin încorporare. 

Pentru toate intențiile și scopurile, compoziția prin încorporarea unui tip anonim este echivalentă cu moștenirea implementării. Structura încorporată este la fel de fragilă ca și clasa de bază. De asemenea, puteți integra o interfață echivalentă cu moștenirea de la o interfață în limbi precum Java sau C ++. Aceasta poate duce chiar la o eroare de execuție care nu este descoperită la momentul compilării dacă tipul de încorporare nu implementează toate metodele de interfață. 

Aici SuperFoo încorporează interfața Fooer, dar nu implementează metodele sale. Compilatorul Go vă va lăsa fericit să creați un nou SuperFoo și să apelați metodele Fooer, dar în mod evident va eșua la timpul de execuție. Aceasta compilează:

tip SuperFooer struct Fooer func principal () s: = SuperFooer  s.Foo2 ()

Rularea acestui program duce la o panică:

panic: eroare de execuție: adresa de memorie invalidă sau dereferență zero a semnalului [semnal 0xb code = 0x1 addr = 0x28 pc = 0x2a78] gorutină 1 [execută]: panic (0xde180, 0xc82000a0d0) /usr/local/Cellar/go/1.6/libexec/ src / runtime / panic.go: 464 + 0x3e6 main.main () /Users/gigi/Documents/dev/go/src/github.com/oop_test/main.go:104 + 0x48 Stare de ieșire 2 Proces finalizat cu cod de ieșire 1

polimorfismul

Polimorfismul este esența programării orientate obiect: abilitatea de a trata obiecte de diferite tipuri în mod uniform, atâta timp cât acestea aderă la aceeași interfață. Go interfețele oferă această capacitate într-un mod foarte direct și intuitiv. 

Iată un exemplu elaborat în care sunt create și stocate într-o felie mai multe creaturi (și o ușă!) Care implementează interfața Dumper și apoi Dump () metoda este solicitată pentru fiecare. Veți observa și alte stiluri de instanțiere a obiectelor.

pachetul principal de import "fmt" tip Creature struct Nume șir Real bool func Dump (c * Creature) fmt.Printf ("Nume: '% s', Real:% t \ n", c.Name, c.Real ) func (c Creature) Dump () fmt.Printf ("Nume: '% s', Real:% t \ n", c.Name, c.Real) type FlyingCreature struct Creature WingSpan int fc FlyingCreature) Dump () fmt.Printf ("Nume: '% s', Real:% t, WingSpan:% d \ n", fc.Name, fc.Real, fc.WingSpan)  tip Dragon struct FlyingCreature de tip Pterodactyl struct FlyingCreature func NewPterodactyl (aripăSpan int) * Pterodactyl animal: = & Pterodactyl FlyingCreature  Dump () de tip Door struct Grosime int String culoare func (d Door) Dump () fmt.Printf ("Door => Grosime:% d, Culoare:% s", d.Thickness, d.Color)  func  creatură: = & creatură "some creature", false, uni: = Unicorn Creature "Unicorn", false,, pet1: = & Pterodactyl FlyingCreature Creature  Pterodactyl, true,, 5,, pet2: = NewPterodactyl (8) door: = & Door  ) Creature: Creature Creature creature, uni.Creature, pet1.Creature, pet2.Creature fmt.Println ("Dump () prin creature embedded type") pentru _, creature: dummy (creare, uni, pet1, pet2, usa fmt.Println ("Dump () prin interfata Dumper") pentru _, dumper: )

Concluzie

Go este un limbaj de programare orientat spre obiecte bona fide. Acesta permite modelarea bazată pe obiecte și promovează cele mai bune practici de utilizare a interfețelor în locul ierarhiilor de tip beton. Mergeți la anumite alegeri sintactice neobișnuite, dar lucrul general cu tipurile, metodele și interfețele se simte simplu, ușor și natural. 

Embedding-ul nu este foarte curat, dar aparent pragmatismul a fost la locul de muncă, iar încorporarea a fost oferită în loc de compoziție numai după nume.

Cod