Pewnego dnia poszedłem na czat Stack Overflow i zobaczyłem frazę, która głosiła, że dziedziczenie, ubytek i polimorfizm są filarami OOP (w tym sensie, że są fundamentalne, podeszwa konstrukcyjna).
Jest też podobne pytanie, które bardzo często zadawano mi na egzaminach na studiach i rozmowach kwalifikacyjnych, a właściwą odpowiedzią zawsze było stwierdzenie zawarte w tytule pytania („Tak, dziedziczenie, enkapsulacja i polimorfizm są filarami OOP ).
Ale na czacie Stack Overflow byłem wyśmiewany, uczestnicy zdecydowanie nie zgadzali się z takim stwierdzeniem. Więc co jest nie tak z tym stwierdzeniem?
Czy wydaje się, że programiści są przeszkoleni w różnych sprawach w szkołach poradzieckich i amerykańskich?
Czy dziedziczenie, enkapsulacja i polimorfizm nie są uważane przez programistów z USA / Wielkiej Brytanii za filary OOP?
źródło
Odpowiedzi:
Są uważani za filary przez wielu programistów, a wiele uczelni uczy OO w ten sposób.
Niestety jest to również widok krótkowzroczny.
OOP ma bardzo mało podstaw, ponieważ w rzeczywistości jest bardzo konceptualny: „Podejdź do projektu swojego programu, myśląc o przedmiotach jako o obiektach - spójne pakiety danych i funkcjonalności”.
I podczas gdy nowoczesny projekt programu źle postrzega robienie rzeczy w sposób „wyłącznie OO”, najbardziej wykwalifikowani programiści zgodzą się, że zasady SOLID (lub niektóre podzbiory) są lepszymi kandydatami na „filary programowania obiektowego” (mimo że stosuje się również do non-OOP). Te w ogóle nie działają z tymi warunkami. Zamiast tego używają pojęć encji programowych (z których obiekty są jednym), interfejsów (z których jeden to C # / Java / itp.
interface
), Abstrakcji i podtypów (z których dziedziczenie jest jedną formą).źródło
tl; dr: Możesz mieć dziedzictwo bez OO, możesz mieć enkapsulację bez OO, możesz mieć polimorfizm bez OO, możesz nawet mieć wszystkie trzy naraz bez OO. Z drugiej strony możesz mieć OO bez dziedziczenia. Ponadto istnieją różne rodzaje enkapsulacji (zorientowane na ADT i OO), IOW nie wszystkie enkapsulacje są OO.
Długa wersja:
Termin „Programowanie obiektowe” został wymyślony przez Alana Kay, więc on decyduje, co to znaczy. I definiuje to w ten sposób :
Jeśli chodzi o implementację, przesyłanie komunikatów jest opóźnionym wywołaniem procedury, a jeśli wywołania procedury są opóźnione, to w czasie projektowania nie można wiedzieć, co wywołać, więc nie można przyjmować żadnych założeń dotyczących konkretnej reprezentacji stanu. Tak naprawdę tak naprawdę chodzi o przesyłanie wiadomości, późne wiązanie jest implementacją przesyłania wiadomości, a konsekwencją tego jest enkapsulacja.
Później wyjaśnił, że „ główną ideą jest„ przesyłanie wiadomości ” ” i żałuje, że nazwał to „obiektowym” zamiast „zorientowanym na wiadomości”, ponieważ termin „zorientowany obiektowo” kładzie nacisk na nieistotne rzeczy (obiekty ) i odwraca uwagę od tego, co jest naprawdę ważne (wiadomości):
(Oczywiście dzisiaj większość ludzi nawet nie skupia się na przedmiotach, ale na klasach, co jest jeszcze bardziej błędne).
Przesyłanie wiadomości ma fundamentalne znaczenie dla OO, zarówno jako metafory, jak i mechanizmu.
Jeśli wyślesz komuś wiadomość, nie wiesz, co ona z nią zrobi. Tylko rzeczą, jaką można zauważyć, jest ich reakcja. Nie wiesz, czy sami przetworzyli wiadomość (tj. Czy obiekt ma metodę), czy przekazali wiadomość komuś innemu (delegacja / proxy), nawet jeśli ją zrozumieli. Na tym polega enkapsulacja, na tym właśnie polega OO. Nie można nawet odróżnić serwera proxy od rzeczywistego, o ile odpowiada on oczekiwaniom.
Bardziej „nowoczesnym” terminem „przesyłanie komunikatów” jest „dynamiczne wysyłanie metod” lub „wirtualne wywołanie metod”, ale traci ono metaforę i skupia się na mechanizmie.
Podobne uwagi znajdują się również w „ Understanding Data Abstraction”, zrewidowanym przez Williama R. Cooka, a także jego Propozycji uproszczonej, nowoczesnej definicji „Object” i „Object Oriented” .
W Smalltalk-72 nie było nawet żadnych przedmiotów! Były tylko strumienie wiadomości, które zostały przeanalizowane, przepisane i przekierowane. Najpierw pojawiły się metody (standardowe sposoby parsowania i przekierowania strumieni wiadomości), później pojawiły się obiekty (grupy metod, które dzielą pewien stan prywatny). Dziedziczenie nastąpiło znacznie później, a klasy wprowadzono jedynie jako sposób na wsparcie dziedziczenia. Gdyby grupa badawcza Kay wiedziała już o prototypach, prawdopodobnie nigdy nie wprowadziliby zajęć.
Każdy programista powinien przeczytać O zrozumieniu abstrakcji danych, ponownie . Wyjaśnia szczegółowo, jaka dokładnie jest różnica między obiektami a abstrakcyjnymi typami danych. Podaje przykłady przy użyciu Javy, co jest niezwykle istotne dla tego pytania, ponieważ zarówno w przykładach ADT, jak i obiektowych używa on dziedziczenia, enkapsulacji i polimorfizmu, ale tylko jeden z przykładów jest zorientowany obiektowo! Innymi słowy: możesz mieć dziedzictwo, enkapsulację i polimorfizm, możesz nawet mieć wszystkie trzy naraz i nadal nie mieć OO.
Z drugiej strony możesz mieć OO bez dziedziczenia. Jak już wspomniałem powyżej: oryginalne wersje Smalltalk (język zaprojektowany przez Alana Kaya, wynalazcę terminu „Programowanie obiektowe”) nie miały dziedzictwa.
Wreszcie, traktat z Orlando omawia delegowanie jako alternatywę dla dziedziczenia oraz to, w jaki sposób różne formy delegowania i dziedziczenia prowadzą do różnych punktów projektowych w przestrzeni projektowej języków zorientowanych obiektowo. (Należy pamiętać, że w rzeczywistości nawet w językach obsługujących dziedziczenie, takich jak Java, ludzie są tak naprawdę uczeni, jak tego unikać, co ponownie wskazuje, że nie jest to konieczne dla OO.)
źródło