Studiowałem programowanie OO, głównie w C ++, C # i Javie. Myślałem, że dobrze to rozumiem, rozumiejąc enkapsulację, dziedziczenie i polimorfizm (a także czytając wiele pytań na tej stronie).
Jedną rzeczą, która wydaje się pojawiać tutaj i jest koncepcja „przekazywania wiadomości”. Najwyraźniej jest to coś, co nie jest używane podczas programowania OO we współczesnych językach głównego nurtu, ale jest obsługiwane przez Smalltalk.
Moje pytania to:
- Co to jest przekazywanie wiadomości? (Czy ktoś może podać praktyczny przykład?)
- Czy jest jakieś wsparcie dla tego „przekazywania wiadomości” w C ++, C # lub Javie?
java
c#
c++
object-oriented
Tomek
źródło
źródło
Odpowiedzi:
Przekazywanie wiadomości oznacza po prostu, że (na bardzo abstrakcyjnym poziomie) podstawowym mechanizmem wykonywania programu są obiekty wysyłające sobie komunikaty. Ważną kwestią jest to, że nazwa i struktura tych wiadomości niekoniecznie muszą być wcześniej ustalone w kodzie źródłowym i same mogą być dodatkowymi informacjami. Jest to ważna część tego, co Alan Kay pierwotnie przewidywał jako „programowanie obiektowe”.
Te języki implementują ograniczoną wersję komunikatów przechodzących przez wywołania metod. Ograniczony, ponieważ zestaw wiadomości, które można wysłać, jest ograniczony do metod zadeklarowanych w klasie. Zaletą tego podejścia jest to, że można go bardzo skutecznie wdrożyć i umożliwia bardzo szczegółową analizę kodu statycznego (co daje wiele przydatnych korzyści, takich jak uzupełnianie kodu).
I odwrotnie, języki, które sugerują „prawdziwe” przekazywanie wiadomości, często mają również definicje metod, jako wygodny sposób na implementację procedur obsługi komunikatów, ale pozwalają klasom na implementację bardziej elastycznych procedur obsługi komunikatów, które umożliwiają obiektowi odbieranie „wywołań metod” o dowolnych nazwach (nie naprawiono w czasie kompilacji).
Przykład w Groovy, który pokazuje siłę tej koncepcji:
wyprodukuje ten XML:
Należy zauważyć, że
records
,car
,country
irecord
są składniowo wywołania metod, ale nie istnieją żadne metody określonej w tej nazwieMarkupBuilder
. Zamiast tego ma funkcję przechwytywania komunikatów catchall, która akceptuje wszystkie wiadomości i interpretuje nazwy wiadomości jako nazwę elementu XML, parametry jako atrybuty, a zamknięcia jako elementy potomne.źródło
sendMessage(property_name, Array of arguments)
igetMessage(property_name, Array of arguments)
statycznych języków?Przekazywanie wiadomości to inny sposób radzenia sobie z potrzebą w kodzie OO, aby jeden obiekt uzyskał inny obiekt (lub potencjalnie sam) do zrobienia czegoś.
W większości współczesnych języków wywodzących się z podejścia C ++ robimy to za pomocą wywołań metod. W tym przypadku wywoływany obiekt (poprzez swoją definicję klasy) umieszcza dużą listę akceptowanych wywołań metod, a następnie koder obiektu wywołującego po prostu zapisuje wywołanie:
W przypadku języków o typie statycznym kompilator może następnie sprawdzić typ wywoływanej rzeczy i potwierdzić, że metoda została zadeklarowana. W przypadku języków dynamicznie wpisywanych odbywa się to w czasie wykonywania.
Ale w gruncie rzeczy dzieje się tak, że pakiet zmiennych jest wysyłany do określonego bloku kodu.
Przekazywanie wiadomości
W językach przekazujących wiadomości (takich jak Cel C) zamiast metod istnieją odbiorniki, ale ogólnie podejście do ich definiowania i wywoływania jest takie samo - różnica polega na sposobie, w jaki jest obsługiwany.
W przekazywanym języku kompilator może sprawdzić, czy odbiornik, do którego zadzwoniłeś, istnieje, ale w najgorszym przypadku wyświetli ostrzeżenie, że nie jest pewien, czy tam jest. Wynika to z faktu, że w czasie wykonywania nastąpi wywołanie bloku kodu na obiekcie odbierającym, przekazując zarówno pakiet zmiennych, jak i podpis odbiorcy, który chcesz wywołać. Ten blok kodu następnie szuka odbiornika i wywołuje go. Jeśli jednak odbiornik nie istnieje, kod po prostu zwróci wartość domyślną.
W rezultacie jedną z osobliwości stwierdzonych podczas przechodzenia z C ++ / Java -> Cel C jest zrozumienie, że można „wywołać metodę” na obiekcie, który nie został zadeklarowany w typie czasu kompilacji, a nawet nie istniał typ wykonania ... i że wywołanie nie spowodowałoby wyrzucenia wyjątku, ale w rzeczywistości wynik zostałby przekazany z powrotem.
Zaletami tego podejścia jest to, że spłaszcza hierarchię podklasy i pozwala uniknąć większości potrzeb związanych z interfejsami / wielokrotnym dziedziczeniem / typami kaczek. Pozwala także obiektom zdefiniować domyślne zachowanie, gdy zostanie poproszony o zrobienie czegoś, dla czego nie ma odbiornika (zwykle „jeśli tego nie zrobię, przekaż żądanie do tego innego obiektu”). Może także uprościć łączenie z wywołaniami zwrotnymi (np. Dla elementów interfejsu użytkownika i zdarzeń czasowych), szczególnie w przypadku języków o typie statycznym, takich jak Java (dzięki czemu przycisk może wywoływać odbiornik „runTest” zamiast wywoływać metodę „actionPerformed” w klasie wewnętrznej „RunTestButtonListener”, który wykonuje wywołanie dla Ciebie).
Wydaje się jednak, że kosztem jest dodatkowe sprawdzenie przez dewelopera, czy wywołanie, które według nich wykonują, znajduje się na właściwym obiekcie z odpowiednim typem i przekazuje odpowiednie parametry we właściwej kolejności, ponieważ kompilator może nie ostrzeże cię, a będzie działał idealnie dobrze w czasie wykonywania (po prostu zwraca domyślną odpowiedź). Można również przypuszczać, że poprawiono wydajność dzięki dodatkowemu spojrzeniu i przekazywaniu parametrów.
Obecnie dynamicznie pisane języki mogą dawać wiele korzyści z OO przekazywanych z mniejszą ilością problemów.
źródło
Architektury przekazywania wiadomości to po prostu systemy, w których każdy komponent jest niezależny od innych, ze wspólnym mechanizmem przekazywania danych między nimi. Możesz traktować wywołania metod jako formę przekazywania wiadomości, ale nie jest to praktyczne - powoduje to zamieszanie. Dzieje się tak dlatego, że jeśli masz klasę z dobrze zdefiniowanymi metodami i jakiś kod, który wywołuje te metody, cała sprawa musi zostać skompilowana razem, łącząc w ten sposób kod i obiekt. możesz zobaczyć, jak jest blisko (gdy wiadomość jest przekazywana, a kompilator wymusza poprawność, ale traci znaczną część elastyczności systemu odsprzęgniętego).
Architektury przekazywania wiadomości często pozwalają na dodawanie obiektów w czasie wykonywania, a częściej na przekazywanie wiadomości do jednego lub większej liczby obiektów. Mogę więc mieć kod, który rozgłasza komunikat „data x is updated” do wszystkich obiektów, które zostały załadowane do systemu, i każdy z nich może podjąć dowolne działanie z tymi informacjami.
Dziwnym przykładem jest sieć. HTTP to system przekazywania wiadomości - przekazujesz komendę czasową i „pakiet danych” do procesu serwera. (np. GET http: \ myserver \ url) Ani twoja przeglądarka, ani serwer internetowy nie dbają o dane, które wysyłasz lub do których je wysyłasz. Serwer przekaże go do kodu, który spakuje kolejny „pakiet” danych i odeśle go z powrotem. Żaden ze składników tego systemu nie wie nic o pracy innych ani o tym, co robią, po prostu znają protokół używany do komunikacji wiadomości.
źródło