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?
Odpowiedz
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:
- Tworzenie protokół o nazwie DownloadingFileProtocol i dodać metod, które trzeba za pobranie pliku. na przykład. urlToDownload, pathToSave, rozbudowa itp
- 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.
- Zobacz, czy ponownie pojawia się nowy podmiot, nie zmienisz żadnego kodu, tylko zaimplementuj metody protokołu.
- A teraz twoja DownloadManager może wejście jako DownloadingFileProtocol zamiast konkretnego modelu, a teraz można żadnego modelu pobrać jako.
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?
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ągaShape
- różnych kolorach -
Red
rozciągaColorful
- Różne rodzaje oświetlenia -
Glowing
rozciągaIlluminated
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.
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ć.
ale czy nie byłeś w stanie dostosować się do wielu protokołów w ObjC? Jak Swift jest inny? – Honey
- 1. Dlaczego wzór Borg jest lepszy niż wzór Singleton w Pythonie
- 2. Dlaczego protokół POP3 przetrwał?
- 3. Czy stan "Jeśli" jest lepszy niż? i odlewanie
- 4. Czy indeks partycjonowany globalnie jest lepszy (szybszy) niż indeks niepartycjonowany?
- 5. Czy jest lepszy sposób niż GOTO w tym scenariuszu?
- 6. Czy jest lepszy sposób powiększania okien w Vimie niż ZoomWin?
- 7. Który przypadek jest lepszy?
- 8. Dlaczego jest `[` lepiej niż `podzbiór`?
- 9. Dlaczego Bootstrap na Twitterze jest lepszy niż responsywne, adaptacyjne motywy dostępne na blogach i frameworkach?
- 10. Dlaczego ".join() jest szybsze niż + = w Pythonie?
- 11. Czy jest jakiś lekki aktor w Akka?
- 12. Potrzebny jest lepszy język szablonowy
- 13. Dlaczego model pudełkowy W3C jest uważany za lepszy?
- 14. Dlaczego jest lepszy (Return IList zamiast listy zwrotów)?
- 15. Który sposób ustawiania wartości pól jest lepszy i dlaczego?
- 16. Dlaczego ICommand jest lepszy od kodu za wywołaniem VM?
- 17. Brak typu lub protokół błąd podczas protokół jest importowany
- 18. Co to jest protokół "JNP"?
- 19. Protokół GKLocalPlayerListener nie jest nazywany
- 20. Dlaczego integracja Verlet jest lepsza niż integracja Eulera?
- 21. Dlaczego === jest szybsze niż == w PHP?
- 22. Dlaczego gets() jest bardziej niebezpieczny niż scanf()?
- 23. Dlaczego string.HasPrefix jest szybszy niż bytes.HasPrefix?
- 24. Dlaczego akumulacja jest szybsza niż cykl prosty?
- 25. Dlaczego DarkGray jest jaśniejszy niż Gray?
- 26. Dlaczego podział jest droższy niż mnożenie?
- 27. Dlaczego Object.keys jest szybszy niż hasOwnProperty?
- 28. Dlaczego \% (\) jest szybsze niż \ (\) w Vimie?
- 29. Dlaczego funkcja isset() jest bardziej wydajna niż "==="?
- 30. Dlaczego .index jest szybszy niż .all?
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
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