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.