2016-03-22 10 views
7

Oglądając samouczek wideo dostarczony przez Apple, wydaje się, że szybka jest językiem programowania zorientowanym na protokół, a jabłko zachęca programistów do używania protokołu niż klasy. Ale z mojego osobistego poglądu nie widzę widocznych korzyści dla protokołu. klasa może być zgodna z protokołem, ale może również dziedziczyć z nadklasy. Możemy dodać rozszerzenie do protokołu, ale możemy też dodać rozszerzenie do klasy. Możemy implementować funkcje w klasach zgodnych z protokołem, ale możemy również zastąpić func w podklasie. Ciągle nie rozumiem, dlaczego potrzebujemy użyć protokołu, a nie klasy. A kiedy powinniśmy użyć protokołu zamiast klasy?Dlaczego protokół jest lepszy niż lekki?

+1

Oto mój przykład: jeśli mamy 'Car', który dziedziczy po' Vehicle' i 'Wood', który dziedziczy po' BuildingMaterial', i chcemy dodać metodę 'burn' do' Car' i 'Wood', a następnie protokół byłby najlepszy. – tktsubota

+0

Nie jestem pewien, do którego filmu się odwołujesz, ale program WWDC 2015 [Protocol-Oriented Programming] (https://developer.apple.com/videos/play/wwdc2015/408/) opisuje, zalety protokołów. – Rob

Odpowiedz

6

Pozwala pobrać przykład pobierania.

was ma klasy bazowej FileDownloadModel i ma 3 podklasy AudioFileDownloadModel, VideoFileDownloadModel, ImageDownloadModel.

Masz DownloadManager że trwa wejście jako FileDownloadModel i wykorzystuje swoją urlToDownload obiekt modelu, aby pobrać plik.

Później wzdłuż linii powiedziano ci, że jest jeszcze jeden model, ale jego przyjście jak UserDownloadModel który podklasa z użytkownika.

Zobacz teraz, że trudno jest obsłużyć taki scenariusz, w którym będziesz musiał zmienić wiele kodu w celu włączenia metod pobierania.

Jak programowanie protokół zorientowany pomoże tutaj:

  1. Tworzenie protokół o nazwie DownloadingFileProtocol i dodać metod, które trzeba za pobranie pliku. na przykład. urlToDownload, pathToSave, rozbudowa itp
  2. Wdrożenie tego samego protokołu w FileDownloadModel i UserDownloadModel. Zobacz korzyść, że nie musisz zmieniać numeru kodu w UserDownloadModel. Po prostu zaimplementujesz metody z DownloadingFileProtocol.
  3. Zobacz, czy ponownie pojawia się nowy podmiot, nie zmienisz żadnego kodu, tylko zaimplementuj metody protokołu.
  4. A teraz twoja DownloadManager może wejście jako DownloadingFileProtocol zamiast konkretnego modelu, a teraz można żadnego modelu pobrać jako.
1

Z protokołami jedna klasa/struktura może być używana jako różne rzeczy. Na przykład, struktura String jest zgodna z wieloma protokołami!

Comparable 
CustomDebugStringConvertible 
Equatable 
ExtendedGraphemeClusterLiteralConvertible 
Hashable 
MirrorPathType 
OutputStreamType 
Streamable 
StringInterpolationConvertible 
StringLiteralConvertible 
UnicodeScalarLiteralConvertible 

Oznacza to, że String może być używany jako 11 różnych rzeczy! Gdy metoda wymaga jednego z powyższych protokołów jako parametru, możesz przekazać ciąg znaków.

"Ale mogę po prostu stworzyć klasę boga, która ma wszystkie metody, które mają protokoły!" argumentowałeś. Pamiętaj, że możesz odziedziczyć tylko jedną klasę w Swift, a dziedziczenie wielu jest tak niebezpieczne, że może sprawić, że twój kod będzie bardzo złożony.

Ponadto za pomocą protokołów można zdefiniować niestandardowe zachowanie klasy. Metoda String jest inna niż Int. Ale oba są kompatybilne z tą funkcją:

func doStuff(x: Hashable) { 

} 

To jest prawdziwy cud protokołów.

Last but not least, protokoły mają sens. Protokoły reprezentują relację "jest rodzajem" lub "mogą być używane jako". Kiedy X może być użyte jako Y, ma sens, że X odpowiada protokołowi Y, prawda?

2

W dużej mierze jest to hierarchia typów. Powiedzmy, że masz obiekt reprezentujący GlowingRedCube, ale chcesz mieć tego typu stosowanego w wielu kodem rodzajowy, który dba o:

  • różnych kształtach - Cube rozciąga Shape
  • różnych kolorach - Red rozciąga Colorful
  • Różne rodzaje oświetlenia - Glowing rozciąga Illuminated

jesteś w tarapatach. Możesz wybrać klasę podstawową i dodać specjalizację: GlowingRedCube rozszerza GlowingCube rozszerza , ale dostajesz bardzo szeroki zestaw klas i nieelastyczny zestaw rzeczy (co jeśli chcesz zrobić SoftRedCube, ale zachowaj wszystkie metody, które masz zdefiniowany dla twojego istniejącego typu czerwonego sześcianu?)

Mógłbyś mieć tylko Cube i mieć właściwości podświetlenia i kształtu, ale wtedy nie otrzymujesz ładnego sprawdzania typu kompilatora: jeśli masz metodę Room.lightUp() i musisz ją przekazać a Cube, musisz sprawdzić, czy ten typ zawiera jakiekolwiek podświetlenie! Jeśli mógłbyś przekazać to tylko Illuminated, kompilator zatrzymałby Cię, gdy tylko spróbujesz.

Protokoły umożliwiają oddzielenie: GlowingRedCube może implementować protokół Illuminated, protokół Colorful i protokół Shape. Z powodu rozszerzeń protokołów można uwzględnić domyślne implementacje funkcji, więc nie trzeba wybierać poziomu hierarchii, do którego ma zostać dołączony.

struct GlowingRedCube: Shape, Colorful, Illuminated { 
// .. 
} 

Skutecznie, protokoły pozwalają dołączyć zachowanie do obiektu, niezależnie od tego, co jeszcze robi tego obiektu.Właśnie dlatego są one używane do takich funkcji, jak delegate i protokoły danych źródłowych: nawet jeśli w większości przypisujesz te rzeczy do ViewController, podstawowy obiekt nie jest istotny, więc możesz być elastyczny w kwestii tego, jak je implementujesz.

W Swift jest dużo więcej niż tylko podstaw: są wyjątkowo wydajne, ponieważ można je dołączyć do wielu różnych konstrukcji kodu: klas, struktur i wyliczeń. To pozwala na naprawdę podejście do protokołu programowania. Jest świetny film o tym podejściu od WWDC last year, ale warto poświęcić trochę czasu na wypróbowanie różnych struktur obiektów, aby poczuć problemy.

9

klasa i protokół to pojęcia ortogonalne. Protokół przecina drzewo klas i dołącza do jednej lub więcej klas o odmiennym pochodzeniu.

Być może umieścić prościej:

  • "klasa" definiuje obiekt jest.
  • "Protokół" definiuje zachowanie obiektu.

Więc masz klasę samochodu:

class Car { 
    var bodyStyle : String 
} 

i klasy Kolor:

class Color { 
    var red : Int 
    var green : Int 
    var blue : Int 
} 

Teraz, bardziej lub mniej oczywiście kolory i samochody są całkowicie niezwiązane jednak załóżmy I chcesz mieć możliwość łatwego przekonwertowania jednego do ciągu znaków, więc mogę debugować za pomocą:

print(Car(...)) 

lub

print(Color(...)) 

Dla dokładnie tym celu język Swift definiuje protokół CustomStringConvertible więc możemy zadeklarować samochodu można wydrukować przy użyciu tego protokołu:

extension Car : CustomStringConvertible { 
    var description : String { get { return "Car: \(bodyStyle)" } } 
} 

i kolor, a także :

extension Color : CustomStringConvertible { 
    var description : String { get { return "Color: \(red) \(green) \(blue)" } } 
} 

Więc gdzie wcześniej potrzebowałbym jednej metody drukowania dla każdej klasy, teraz potrzebuję tylko jednej metody drukowania, która wygląda na coś ike:

func print(data:CustomStringConvertible) { 
    let string = data.description 
    ... bunch of code to actually print the line 
} 

Jest to możliwe dlatego, oświadczając, że klasa implementuje protokół jest obietnica, że ​​mogę użyć metod z protokołem, wiedząc, że są one wdrażane i (przypuszczalnie) robić to, co się spodziewać.

+0

ale czy nie byłeś w stanie dostosować się do wielu protokołów w ObjC? Jak Swift jest inny? – Honey

Powiązane problemy