Protocoale si extensii – Swift 3

De ce este nevoie să introducem protocoale în Swift atât timp cât avem de-a face cu clase și putem subclasa?
Swift este Protocol Object Oriented. În Swift protocoalele reprezintă o modalitate bună de a defini un set de funcționalități necesare pe care clasele sau structurile le pot adopta.
Pentru a fi mai clari, un protocol oferă informații despre ce poate face o clasă, nu neapărat ce este o clasă.

De ce protocol și nu sub-clasare?

Să luăm un exemplu de sub-clasare:

class Animal {
    func ceZgomotFace() { fatalError("Implementeaza cod pentru functie!") }
}

Bun, avem deci de-a face cu o clasa abstractă care nu poate fi instanțiată direct ci de către subclase.

Acum introducem o subclasă numită Caine care va încărca metoda ceZgomotFace

class Caine: Animal {
    override func ceZgomotFace() { print("HamHam!") }
}

let rex = Caine()
rex.ceZgomotFace() //prints "HamHam!"

Ce se întâmplă dacă ori uităm să încărcăm în subclasă metoda ceZgomotFace sau să apelăm direct o instanță de Animal?

let iepure = Animal()
iepure.ceZgomotFace() //CRASH

class Cat: Animal { }
let pisi = Cat()
pisi.ceZgomotFace() //CRASH

Prin urmare, aspectul cel mai deranjant este că în orice subclasă am avea pentru o clasă abstractă, trebuie să implementăm metodele din clasa mamă – Animal.

Swift vine cu o abordare interesantă în acest caz – protocolul.

protocol Sunet {
    func ceZgomotFace() 
}

Nu ne interesează în acest moment de ce tip este și cine va implementa protocolul Sunet, important pentru noi va fi doar faptul că metoda ceZgomotFace va fi definită în clasa conformă cu protocolul.

class Caine: Sunet {
    func ceZgomotFace() {
        print("Woof!")
    }
}
 
class Arbore: Sunet {
    func ceZgomotFace() {
        print("Fasssss!")
    }
}
 
class iPhone: Sunet {
    func ceZgomotFace() {
        print("Clinc-clinc!")
    }
}

Nimic spectaculos până acum. Cam același lucru-l fac și subclasele.

Dar… avem protocol extensions care de fapt definește Swift ca și limbaj obiectual orientat protocol.

class Fiinta {
    func mananca() {
    print("mi-e foame!")
    }
}

protocol Sunet {
    func ceZgomotFace() 
}

Avem o clasă Fiinta care implementează metoda mananca() și un protocol Sunet pe care dacă cineva îl va folosi va trebuie să implementeze ceZgomotFace()

extension Sunet where Self: Fiinta {
    func rade() {
        print("HAHA!");
    }

    func plange() {
        print("HOHO!");
    }
}

Extensia protocolului Sunet va fi valabilă doar pentru clasa Ființă și pentru subclasele sale, doar ele având acces la metodele rade și plange

Și acum să vedem puterea protocolului.

class Om : Fiinta, Sunet { 
    func ceZgomotFace() {
        print("Pot face ce zgomot vreau!");
    }
}

class Iphone : NSObject, Sunet { 
    func ceZgomotFace() {
        print("Clinc-clinc!");
    }
}

Clasa Om va mosteni clasa de baza Fiinta și, de asemenea, va putea folosi toate metodele din extensia Sunet.
Prin urmare, o instanta Om va putea accesa metodele din extensia Sunet: rade() și plange() dar va implementa și metoda din protocol – ceZgomotFace().

Prin urmare,

let georgel = Om()
georgel.ceZgomotFace() // Pot face ce zgomot vreau!
georgel.rade() // HAHA!
georgel.plange() // HOHO!

Clasa Greiere va putea folosi doar metodele definite în protocolul Sunet, neavând acces la extensia de protocol deoarece nu are ca Fiinta ca și clasă de bază.

Share Button

Stefan

Leave a Reply

Your email address will not be published.