Programowanie aspektowe a programowanie obiektowe


199

Jak większość programistów tutaj i na całym świecie, od wielu lat rozwijam systemy oprogramowania przy użyciu technik programowania obiektowego (OOP). Więc kiedy czytam, że programowanie aspektowe (AOP) rozwiązuje wiele problemów, których tradycyjne OOP nie rozwiązuje całkowicie lub bezpośrednio, zatrzymuję się i myślę, czy to prawda?

Przeczytałem wiele informacji, próbując nauczyć się kluczy tego paradygmatu AOP i jestem w tym samym miejscu, więc chciałem lepiej zrozumieć jego zalety w tworzeniu aplikacji w świecie rzeczywistym.

Czy ktoś ma odpowiedź?


7
Wszystkie odpowiedzi były bardzo dobre, jest to idealny przypadek dla jednej odpowiedzi edytowanej przez społeczność, która połączyłaby je wszystkie. Wszyscy mówią to samo, ale na różne sposoby i używając różnych przykładów, które zwiększają ogólną wartość
Vinko Vrsalovic

Odpowiedzi:


323

Dlaczego „vs”? To nie jest „vs”. Z programowania orientacyjnego można korzystać w połączeniu z programowaniem funkcjonalnym, ale także w połączeniu z programowaniem obiektowym. To nie jest „vs”, to „Programowanie aspektowe z programowaniem obiektowym”.

Dla mnie AOP jest rodzajem „metaprogramowania”. Wszystko, co robi AOP, można również zrobić bez tego, po prostu dodając więcej kodu. AOP po prostu oszczędza Ci pisania tego kodu.

Wikipedia ma jeden z najlepszych przykładów tego metaprogramowania. Załóżmy, że masz klasę graficzną z wieloma metodami „set ... ()”. Po każdej ustawionej metodzie zmieniły się dane grafiki, a więc grafika uległa zmianie, a więc grafika musi zostać zaktualizowana na ekranie. Załóżmy, że odmalowujesz grafikę, musisz wywołać „Display.update ()”. Klasyczne podejście polega na rozwiązaniu tego problemu przez dodanie większej ilości kodu . Na końcu każdej metody zestawu, którą piszesz

void set...(...) {
    :
    :
    Display.update();
}

Jeśli masz 3 ustawione metody, nie stanowi to problemu. Jeśli masz 200 (hipotetycznych), bolesne jest dodawanie tego wszędzie. Również za każdym razem, gdy dodajesz nową metodę zestawu, pamiętaj, aby nie zapomnieć o dodaniu jej na końcu, w przeciwnym razie właśnie stworzyłeś błąd.

AOP rozwiązuje to bez dodawania ton kodu, zamiast tego dodajesz aspekt:

after() : set() {
   Display.update();
}

I to wszystko! Zamiast pisać kod aktualizacji samodzielnie, po prostu mówisz systemowi, że po osiągnięciu punktu set (), musi on uruchomić ten kod i uruchomi ten kod. Nie musisz aktualizować 200 metod, nie musisz się upewnić, że dodasz ten kod do nowej metody set. Dodatkowo potrzebujesz tylko wycięcia:

pointcut set() : execution(* set*(*) ) && this(MyGraphicsClass) && within(com.company.*);

Co to znaczy? Oznacza to, że metoda ma nazwę „zestaw *” (* oznacza, że ​​po zestawie może pojawić się dowolna nazwa), niezależnie od tego, co metoda zwraca (pierwsza gwiazdka) lub jakie parametry przyjmuje (trzecia gwiazdka) i jest to metoda MyGraphicsClass, a to klasa jest częścią pakietu „com.company. *”, to jest to punkt set (). A nasz pierwszy kod mówi „ po uruchomieniu dowolnej metody, która jest ustawionym punktem odniesienia, uruchom następujący kod”.

Zobacz, jak AOP elegancko rozwiązuje tutaj problem? Właściwie wszystko opisane tutaj można zrobić w czasie kompilacji. Preprocesor AOP może po prostu zmodyfikować źródło (np. Dodać Display.update () na końcu każdej metody set-pointcut), a nawet skompilować samą klasę.

Jednak ten przykład pokazuje również jedną z dużych wad AOP. AOP faktycznie robi coś, co wielu programistów uważa za „ Anti-Pattern ”. Dokładny wzór nazywa się „ Działanie na odległość ”.

Działanie na odległość jest anty-wzorcem (rozpoznanym powszechnym błędem), w którym zachowanie w jednej części programu różni się bardzo w zależności od trudnych lub niemożliwych do zidentyfikowania operacji w innej części programu.

Jako nowicjusz w projekcie, mógłbym po prostu przeczytać kod dowolnej metody set i uznać, że jest zepsuty, ponieważ wydaje się, że nie aktualizuje wyświetlacza. Nie widzę , patrząc tylko na kod metody set, że po jej wykonaniu jakiś inny kod zostanie „magicznie” wykonany w celu aktualizacji wyświetlacza. Uważam to za poważny minus! Wprowadzając zmiany w metodzie, można wprowadzić dziwne błędy. Dalsze zrozumienie przepływu kodu, w którym pewne rzeczy wydają się działać poprawnie, ale nie są oczywiste (jak powiedziałem, po prostu magicznie działają ... jakoś), jest naprawdę trudne.

Aktualizacja

Żeby wyjaśnić, że: Niektórzy ludzie mogą mieć wrażenie, że mówię, że AOP jest czymś złym i nie należy go stosować. Nie to mówię! AOP to w rzeczywistości świetna funkcja. Po prostu mówię „Używaj go ostrożnie”. AOP spowoduje problemy tylko wtedy, gdy pomieszasz normalny kod i AOP dla tego samego aspektu . W powyższym przykładzie mamy Aspekt aktualizacji wartości obiektu graficznego i malowania zaktualizowanego obiektu. To jest właściwie jeden aspekt. Problem stanowi dodanie połowy tego kodu jako normalnego kodu, a druga połowa jego aspektu.

Jeśli użyjesz AOP do zupełnie innego aspektu, np. Do logowania, nie napotkasz problemu z anty-wzorcem. W takim przypadku nowicjusz w projekcie może zastanawiać się: „Skąd pochodzą te wszystkie komunikaty dziennika? Nie widzę żadnych danych wyjściowych dziennika w kodzie”, ale to nie jest duży problem. Zmiany, które wprowadza w logice programu, prawie nie zepsują funkcji logów, a zmiany wprowadzone w logi programu prawie nie złamią logiki programu - te aspekty są całkowicie oddzielone. Używanie AOP do rejestrowania ma tę zaletę, że kod programu może w pełni skoncentrować się na robieniu tego, co powinien, i nadal możesz mieć wyrafinowane rejestrowanie, bez konieczności zapełniania swojego kodu setkami komunikatów dziennika. Również po wprowadzeniu nowego kodu magicznie logowane wiadomości pojawią się we właściwym czasie z odpowiednią treścią.

Tak więc dobrym zastosowaniem AOP w moim przykładzie byłoby zawsze rejestrowanie, jeśli jakakolwiek wartość została zaktualizowana za pomocą ustawionej metody. Nie stworzy to anty-wzoru i prawie nigdy nie będzie przyczyną żadnego problemu.

Można powiedzieć, że jeśli możesz łatwo nadużyć AOP do spowodowania tak wielu problemów, nie warto używać tego wszystkiego. Jakiej technologii nie można jednak nadużywać? Możesz nadużywać enkapsulacji danych, możesz nadużywać dziedziczenia. Niemal każda użyteczna technologia programowania może być nadużywana. Rozważmy język programowania tak ograniczony, że zawiera on tylko funkcje, których nie można nadużywać; język, w którym funkcje mogą być używane tylko tak, jak pierwotnie były przeznaczone. Taki język byłby tak ograniczony, że można by go argumentować nawet w przypadku programowania w świecie rzeczywistym.


4
Rejestrowanie wydaje się być konkretnym przykładem, w którym AOP nie powoduje działania na odległość. W tej chwili wikipedia jako przykład użycia aspektu do kontroli bezpieczeństwa, które naprawdę sprawiają, że program jest o wiele bardziej zrozumiały.
kizzx2

7
@ kizzx2: Właściwie świetny moment na logowanie - to najlepszy przykład, jaki widziałem do tej pory AOP, nie wiedząc wiele o AOP. Dzięki za udostępnienie!
wpadki

@ Mecki, Twój przykład jest zbyt uproszczony i nie odzwierciedla ogólnego przypadku użycia. W twoim przykładzie Display.updatenie bierze żadnych argumentów. Co jeśli będziemy musieli przekazać argumenty (np. Zwykle logfunkcja wymagałaby messageparametru)? Czy nie musielibyśmy wówczas dodawać dużej ilości kodu typu Boiler Plate, aby zrobić to w sposób AOP?
Pacerier

3
@Pacerier Mój przykład jest uproszczony, ponieważ SO nie jest forum nauczania. Właśnie odpowiadałem na pytanie pytającego, prawdopodobnie o wiele bardziej szczegółowe, niż byłoby to konieczne. Jeśli chcesz dowiedzieć się więcej o AOP, spróbuj przeczytać dokumentację programisty, a jeśli masz szczegółowe pytanie, dlaczego nie zadać go tutaj? Nie, nie w komentarzu, idź i stwórz nowe pytanie, ponieważ o to właśnie chodzi w SO. Jestem pewien, że ktoś będzie w stanie rozwiać twoje wątpliwości w odpowiedzi.
Mecki,

2
@Pacerier Przepraszam, ale nie rozumiem, o co ci chodzi. Zobacz tutaj: stackoverflow.com/a/8843713/15809 Ten kod rejestruje każde wywołanie każdej metody publicznej, w tym wszystkie typy argumentów i wartości metod. Piszecie to dokładnie raz, a do każdej metody dodany jest zerowy kod, to tylko kod pokazany w odpowiedzi.
Mecki

29

programowanie aspektowe stanowi dobry sposób na wdrożenie przekrojowych zagadnień, takich jak rejestrowanie, bezpieczeństwo. Te przekrojowe koncesje są elementami logiki, które muszą być stosowane w wielu miejscach, ale w rzeczywistości nie mają nic wspólnego z logiką biznesową.

Nie powinieneś widzieć AOP jako zamiennika OOP, a raczej jako miłego dodatku, który sprawia, że ​​twój kod jest bardziej czysty, luźno powiązany i skupiony na logice biznesowej. Stosując AOP, uzyskasz 2 główne korzyści:

  1. Logika każdego problemu znajduje się teraz w jednym miejscu, w przeciwieństwie do rozproszenia w całej bazie kodu.

  2. klasy są czystsze, ponieważ zawierają tylko kod dla ich podstawowej troski (lub podstawowej funkcjonalności), a drugorzędne kwestie zostały przeniesione do niektórych aspektów.


27

OOP i AOP nie wykluczają się wzajemnie. AOP może być dobrym dodatkiem do OOP. AOP jest szczególnie przydatny do dodawania standardowego kodu, takiego jak rejestrowanie, śledzenie wydajności itp. Do metod bez zapychania kodu metody tym standardowym kodem.


10

Myślę, że nie ma ogólnej odpowiedzi na to pytanie, ale jedną rzeczą, na którą należy zwrócić uwagę, jest to, że AOP nie zastępuje OOP, ale dodaje pewne cechy rozkładu, które dotyczą tak zwanej tyranii dominującej kompozycji ( 1 ) (lub problemów przekrojowych).

Z pewnością pomaga w niektórych przypadkach, o ile masz kontrolę nad narzędziami i językami używanymi w konkretnym projekcie, ale także dodaje nowy poziom złożoności w zakresie interakcji aspektów i potrzeby dodatkowych narzędzi, takich jak AJDT, aby nadal rozumieć twój program.

Gregor Kiczales wygłosił kiedyś interesującą rozmowę wprowadzającą na temat AOP na Google Tech Talks, którą polecam obejrzeć: Programowanie zorientowane na aspekty: Radykalne badania w modułowości .


8

Przede wszystkim AOP nie zastąpi OOP. AOP rozszerza OOP. Pomysły i praktyki OOP pozostają aktualne. Posiadanie dobrego projektu obiektu prawdopodobnie ułatwi jego rozszerzenie o aspekty.

Myślę, że pomysły, które przynosi AOP, są ważne. Musimy znaleźć sposoby na wdrożenie przekrojowych problemów dotyczących różnych klas w twoim programie bez konieczności zmiany samych klas. Myślę jednak, że AOP ostatecznie stanie się częścią innych narzędzi, których używamy, a nie oddzielnym narzędziem lub techniką. Już to widzimy.

Kilka dynamicznych języków, takich jak Ruby i Python, ma konstrukcje językowe, takie jak mixiny, które rozwiązują te same problemy. To wygląda bardzo podobnie do AOP, ale jest lepiej zintegrowane z językiem.

Spring i Castle oraz kilka innych struktur wstrzykiwania zależności mają opcje dodawania zachowania do klas, które wstrzykują. Jest to sposób robienia tkactwa w czasie wykonywania i myślę, że ma to duży potencjał.

Nie sądzę, że będziesz musiał nauczyć się zupełnie nowego paradygmatu, aby korzystać z AOP. Pomysły są interesujące, ale powoli są przyswajane przez istniejące narzędzia i języki. Po prostu bądź na bieżąco i wypróbuj te narzędzia.



1

Spóźniłem się z odpowiedzią na to pytanie, ale jest to jeden z moich ulubionych tematów, dlatego podzielę się swoim poglądem.

OOP służy głównie do organizowania logiki biznesowej, podczas gdy AOP pomaga organizować niefunkcjonalne rzeczy, takie jak audyt, rejestrowanie, zarządzanie transakcjami, bezpieczeństwo itp.

W ten sposób możesz oddzielić logikę biznesową za pomocą logiki non-fiction, która czyni kod czystszym.

Zaletą wydry jest to, że możesz konsekwentnie stosować porady (np. Audyt) bez implementacji jakiegokolwiek interfejsu, który zapewnia dużą elastyczność modyfikacji bez dotykania logiki biznesowej

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.