W pierwszym semestrze zapoznaliśmy się z pojęciami OOP, takimi jak enkapsulacja, ukrywanie danych, modułowość, dziedziczenie itd. Za pośrednictwem Java i UML. (Java to mój pierwszy język programowania)
Żadna z nich nie jest koncepcją OOP. Wszystkie istnieją poza OO, niezależnie od OO, a wiele z nich zostało nawet wymyślonych przed OO.
Jeśli więc uważasz, że o to właśnie chodzi w OO, to twój wniosek jest słuszny: możesz robić wszystkie w językach proceduralnych, ponieważ nie mają one nic wspólnego z OO .
Na przykład jeden z najważniejszych artykułów na temat modułowości dotyczy kryteriów, które należy stosować w rozkładaniu układów na moduły . Nie ma tam wzmianki o OO. (Został napisany w 1972 roku, do tego czasu OO wciąż była niejasną niszą, mimo że ma już ponad dekadę).
Podczas gdy abstrakcja danych jest ważna w OO, jest bardziej konsekwencją podstawowej funkcji OO (Messaging) niż funkcji definiującej. Ponadto bardzo ważne jest, aby pamiętać, że istnieją różne rodzaje abstrakcji danych. Dwa najpopularniejsze rodzaje abstrakcji danych, które są obecnie w użyciu (jeśli zignorujemy „brak jakiejkolwiek abstrakcji”, który prawdopodobnie nadal jest używany częściej niż pozostałe dwa połączone), to abstrakcyjne typy danych i obiekty . Tak więc, mówiąc „ukrywanie informacji”, „enkapsulację” i „abstrakcję danych”, nie powiedziałeś nic o OO, ponieważ OO jest tylko jedną formą pozyskiwania danych, a obie te rzeczy są zasadniczo różne:
- W przypadku abstrakcyjnych typów danych mechanizmem abstrakcji jest system typów ; to system typów ukrywa implementację. (System typów niekoniecznie musi być statyczny.) W Objects implementacja jest ukryta za interfejsem proceduralnym , który nie wymaga typów. (Na przykład można go zaimplementować za pomocą zamknięć, jak to ma miejsce w ECMAScript).
- Dzięki abstrakcyjnym typom danych instancje różnych ADT są od siebie enkapsulowane, ale instancje tego samego ADT mogą sprawdzać i uzyskiwać dostęp do wzajemnej reprezentacji i prywatnej implementacji. Obiekty są zawsze otoczone wszystkim . Tylko sam obiekt może sprawdzić swoją reprezentację i uzyskać dostęp do swojej prywatnej implementacji. Żaden inny obiekt , nawet inne obiekty tego samego typu, inne instancje tej samej klasy, inne obiekty mające ten sam prototyp, klony obiektu lub cokolwiek innego, co może to zrobić. Żaden .
Nawiasem mówiąc, oznacza to, że w Javie klasy nie są obiektowe. Dwie instancje tej samej klasy mogą uzyskać dostęp do wzajemnej reprezentacji i prywatnej implementacji. Dlatego instancje klas nie są obiektami, w rzeczywistości są instancjami ADT. Java interface
s, jednak nie dostarczają danych abstrakcji obiektowego. Innymi słowy: tylko instancje interfejsów są obiektami w Javie, instancje klas nie.
Zasadniczo w przypadku typów można używać tylko interfejsów. Oznacza to, że typy parametrów metod i konstruktorów, typy zwracanych metod, typy pól instancji, pola statyczne i pola lokalne, argument dla instanceof
operatora lub operatora rzutowania oraz argumenty typu dla konstruktora typu ogólnego muszą zawsze być interfejsami. Klasy można używać tylko bezpośrednio za new
operatorem, nigdzie indziej.
Na przykład dla modułowości możemy po prostu podzielić program na wiele małych programów, które wykonują dobrze zdefiniowane zadania, których kod jest zawarty w osobnych plikach. Programy te współdziałałyby ze sobą poprzez dobrze zdefiniowane dane wejściowe i wyjściowe. Pliki mogą być chronione (szyfrowane?) W celu uzyskania enkapsulacji. Aby ponownie użyć kodu, możemy po prostu wywołać te pliki, ilekroć są one potrzebne w nowych programach. Czy to nie oddaje wszystkiego, czym jest OOP, czy brakuje mi czegoś bardzo oczywistego?
Co opisujesz jest OO.
To naprawdę dobry sposób na myślenie o OO. W rzeczywistości dokładnie to mieli na myśli oryginalni wynalazcy OO. (Alan Kay poszedł o krok dalej: wyobrażał sobie wiele małych komputerów wysyłających do siebie wiadomości przez sieć.) To, co nazywacie „programem”, jest zwykle nazywane „obiektem”, a zamiast „połączenia” zwykle mówimy „wysłać wiadomość” „.
Orientacja obiektowa polega na przesyłaniu wiadomości (inaczej dynamicznej wysyłce ). Termin „zorientowany obiektowo” został ukuty przez dr Alana Kaya, głównego projektanta Smalltalk, i definiuje go następująco :
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.
Rozbijmy to:
- przesyłanie wiadomości („metoda wirtualnej wysyłki”, jeśli nie znasz Smalltalk)
- proces stanu powinien być
- zachowane lokalnie
- chroniony
- ukryty
- 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 komunikatów, późne wiązanie jest implementacją przesyłania komunikatów, a jego konsekwencją 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 trochę się starałem, 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 stworzenia świetnych i sprawdzalnych systemów jest znacznie więcej, aby zaprojektować sposób komunikacji modułów, a nie ich wewnętrzne właściwości i zachowania. 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 zajęciach, 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 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 wiadomości” jest „dynamiczna wysyłka metod” lub „wirtualne wywołanie metody”, ale traci ono metaforę i skupia się na mechanizmie.
Istnieją więc dwa sposoby spojrzenia na definicję Alana Kay: jeśli spojrzysz na nią samodzielnie, możesz zauważyć, że przesyłanie wiadomości jest w zasadzie opóźnionym wywołaniem procedury, a późne wiązanie oznacza enkapsulację, więc możemy stwierdzić, że # 1 i # 2 są w rzeczywistości zbędne, a OO polega na późnym wiązaniu.
Później wyjaśnił jednak, że ważną rzeczą jest przesyłanie wiadomości, dlatego możemy spojrzeć na to z innej strony: przesyłanie wiadomości jest opóźnione. Otóż, gdyby przesyłanie wiadomości było jedyną możliwą rzeczą, to # 3 byłoby trywialnie prawdziwe: jeśli jest tylko jedna rzecz, a ta sprawa jest spóźniona, wówczas wszystkie rzeczy są spóźnione. Po raz kolejny enkapsulacja wynika z przesyłania wiadomości.
Podobne uwagi znajdują się również w „ Understanding Data Abstraction”, zrewidowanym przez Williama R. Cooka, a także w jego Propozycji dotyczącej uproszczonych, nowoczesnych 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 możliwości [dokładnie] wiedzieć, jaka operacja zostanie wykonana 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 współużytkują 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ęć.
Benjamin Pierce w typach i językach programowania argumentuje, że cechą definiującą orientację obiektową jest otwarta rekurencja .
Tak więc: według Alana Kay, OO polega na przesyłaniu wiadomości. Według Williama Cooka, OO polega na dynamicznej wysyłce metod (co tak naprawdę jest tym samym). Według Benjamina Pierce'a w OO chodzi o Open Recursion, co w zasadzie oznacza, że autoreferencje są dynamicznie rozwiązywane (a przynajmniej tak należy się zastanowić) lub, innymi słowy, przesyłanie wiadomości.
Jak widać, osoba, która ukuła termin „OO”, ma raczej metafizyczne spojrzenie na przedmioty, Cook ma raczej pragmatyczny pogląd, a Pierce bardzo rygorystyczny pogląd matematyczny. Ale ważne jest to, że filozof, pragmatyk i teoretyk są zgodni! Wiadomości to jeden filar OO. Kropka.
Zauważ, że nie ma tu mowy o dziedziczeniu! Dziedziczenie nie jest niezbędne dla OO. Ogólnie rzecz biorąc, większość języków OO ma jakiś sposób ponownego wykorzystania implementacji, ale niekoniecznie musi to być dziedziczenie. Może to być na przykład jakaś forma przekazania uprawnień. W rzeczywistości 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 projektowania w przestrzeni projektowania 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ć, ponownie wskazując, że nie jest to konieczne dla OO.)