Dlaczego dziedziczenie, hermetyzacja i polimorfizm nie są filarami OOP? [Zamknięte]

16

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?

PaulD
źródło
7
Twoje pytanie nie ma kontekstu; nie wiemy, co myśleli ludzie na czacie SO i na co odpowiadali. Może możesz połączyć się z rozmową w pokoju rozmów, abyśmy mogli na nią rzucić okiem? To powiedziawszy, myślę, że najlepiej to rozwiązać na czacie, niż tutaj.
Robert Harvey
1
@Robert, za dużo czasu minęło. Wątpię, czy w ogóle mogę znaleźć link do rozmowy. Ale zgadzam się, że kontekst jest ważny. Nie chodzi o to, żeby kogoś obwiniać, ani przedstawiać się jako niewinna ofiara agresji na czacie. Chcę tylko poznać prawdę.
PaulD,
5
Salon. Czy najpierw założyłeś kombinezon ognioodporny?
Robert Harvey
1
Jedyne znaczenie, jakie mogę nadać zdaniu, to albo „możesz mieć OOP bez żadnego z nich” (to prawda, ale nie ma sensu przynajmniej dla enkapsulacji), albo „możesz używać ich poza OOP”, albo coś w tym rodzaju.
SJuan76,
2
Imo OO ma tylko jeden filar, a mianowicie: „państwo”. Gdy mózg myśli w stanie, dostajesz OO.
Pieter B

Odpowiedzi:

40

Czy dziedziczenie, enkapsulacja i polimorfizm nie są uważane przez programistów z USA / Wielkiej Brytanii za filary OOP?

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.

  • Dziedziczenie jest tylko jednym mechanizmem stosowanym do implementacji OOP i może być nadużywane, aby nie robić OOP.
  • Hermetyzacja to koncepcja przydatna do programowania wszelkiego rodzaju, OOP i nie.
  • Polimorfizm to… cecha (?) Opisująca zachowanie obliczeń. Istnieje wiele sposobów na osiągnięcie polimorfizmu, z których nie wszystkie są specyficzne dla OO.

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ą).

Telastyn
źródło
10
Przyzwoita odpowiedź na pytanie, na które zasadniczo nie można odpowiedzieć.
Robert Harvey
3
Czy istnieje OOP?
Tulains Córdova,
5
Twierdziłbym, że tylko enkapsulacja jest „filarem” OOP. Największa różnica między OOP a programowaniem strukturalnym polega na tym, że obiekty zawierają kod i dane, a nie tylko dane (np. Klasyczną strukturę C). Pozostałe dwa pojęcia są używane głównie w językach OO, ale nie są ograniczone do OO ani przez niego wymagane.
3
@Snowman Encapsulation nie ogranicza się również do OOP. Ludzie cały czas implementują abstrakcyjne typy danych w językach C i funkcjonalnych.
Doval,
2
I @ JörgWMittag miał dobrą odpowiedź na temat przesyłania wiadomości. Pomysł przesyłania wiadomości koniecznie wymaga enkapsulacji. Wiadomości są zwykle przekazywane do funkcji lub metody obiektu, który następnie działa na stan w nim zawarty . Nie oznacza to, że języki inne niż OO również nie mogą przekazywać wiadomości ani hermetyzować, tylko że są to podstawowe idee OOP.
23

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 :

OOP oznacza dla mnie tylko wysyłanie wiadomości, lokalne przechowywanie, ochronę i ukrywanie procesów państwowych oraz ekstremalne późne wiązanie wszystkich rzeczy.

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):

Tylko delikatne przypomnienie, że na ostatnim OOPSLA zadałem sobie trud, aby przypomnieć wszystkim, że Smalltalk nie jest NIE tylko składnią ani biblioteką klas, nie dotyczy nawet klas. Przykro mi, że już dawno wymyśliłem termin „obiekty” w tym temacie, ponieważ wielu ludzi skupia się na mniejszym pomyśle.

Wielkim pomysłem jest „przesyłanie wiadomości” - na tym właśnie polega jądro Smalltalk / Squeak (i ​​jest to coś, czego nigdy nie ukończono w fazie Xerox PARC). Japończycy mają małe słowo - ma - na „to, co jest pomiędzy” - być może najbliższym angielskim odpowiednikiem jest „pełnoekranowy”. Kluczem do tworzenia świetnych i sprawdzalnych systemów jest znacznie więcej niż projektowanie ich modułów, a nie ich wewnętrznych właściwości i zachowań. Pomyśl o Internecie - aby żyć, (a) musi pozwalać na wiele różnych rodzajów pomysłów i realizacji, które wykraczają poza jakikolwiek pojedynczy standard, i (b) umożliwiać różne stopnie bezpiecznej interoperacyjności między tymi pomysłami.

(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” .

Dynamiczna wysyłka operacji jest podstawową cechą obiektów. Oznacza to, że wywołana operacja jest dynamiczną właściwością samego obiektu. Operacji nie można zidentyfikować statycznie i ogólnie nie ma sposobu na dokładne wykonanie operacji w odpowiedzi na dane żądanie, poza uruchomieniem go. Jest to dokładnie to samo, co w przypadku pierwszorzędnych funkcji, które są zawsze wysyłane dynamicznie.

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.)

Jörg W Mittag
źródło
Możesz mieć „dziedziczenie”, „polimorfizm” i „dziedziczenie” ... wydaje się, że gdzieś tam jest literówka :)
slebetman
1
Ta odpowiedź sprawia, że ​​żałuję, że nie możemy również „ulubionych” odpowiedzi.
Chan-Ho Suh
Definicja Alana Kay jest nieaktualna. OO potrzebuje dziedziczenia, a jeśli możesz wykonać zarówno powiązanie w czasie wykonywania, jak i w czasie kompilacji, tak jak w C ++, uzyskasz wydajność na poziomie równym C.
Erik Alapää
Nie, jego definicja jest poprawna. Wcale nie potrzebujesz dziedziczenia. Języki prototypowe nie używają dziedziczenia jak C ++ i nadal są OO. Dziedziczenie służy tylko do ponownego użycia kodu, nie jest to nawet najlepszy sposób, na przykład istnieje wiele lepszych języków, które mają na przykład mixiny. Nie ma to również nic wspólnego z wiązaniem, ponieważ możesz mieć dynamiczne wysyłanie, nawet w C ++, kiedy możesz używać metod wirtualnych. Wydajność nie ma z tym nic wspólnego, są to koncepcje wysokiego poziomu, nie mają żadnej wydajności. W rzeczywistości można zaimplementować przekazywanie wiadomości w C i być OO
Luiz Felipe