Poprawne zaprojektowanie aspektu

0

Cześć, napotkałem się z pewnym problemem i pierwszy raz w życiu chcę użyć aspektu. Otóż:

mam jakaś klasę i ona ma pewne, intowe pole.. nazwijkmy je "random". I teraz tak. Chciałbym aby to pole zostało update'owane za każdym razem gdy:

  • wywołuję odpowiednią metodę tej klasy
  • tworzę obiekt tej klasy
  • pobieram tą obiekt tej klasy z bazy danych (ta klasa to encja).

Po prostu chciałbym, aby przy jakiejkolwiek operacji na tym obiekcie to pole automatycznie się updatowało. Najbardziej prymitywny sposób no to sobie stworzyć do tego metodę publiczną i wywoływać w każdym potrzebnym miejscu, ale to przecież zaśmieca kod niepotrzebną logiką. Ta metoda wyglądałaby mniej więcej tak:

void generateNewRandomValue() {
    this.random = new Random().nextInt();
}

Lepiej to zrobić jako aspekt. Tylko nie wiem teraz czy mogę ukryć to pole i nie udostępniać żadnej publicznej metody modyfikującej to pole czy lepiej udostępnić tą metodę i za pomocą niej w aspekcie generować tego nowego randoma. No ale to drugie rozwiązanie zaśmieca api klasy, bo tak naprawdę nic poza aspektem nie będzie wywoływało tej metody.

Porady ?

Pozdrawiam

1

API to jest to co widać na zewnątrz, czyli jeżeli będzie to prywatna metoda to nie ma najmniejszego problemu.

Pytanie jak chcesz ten aspekt zapiąć.

  • AspektJ - jedna linia, czyli tyle samo ile wywołanie metody
  • Dynamiczne proxy - brzydkie tworzenie, zmieniona klasa
  • Wzorzec dekorator - czyste, ale nie ma sensu jeżeli obiekt bez dekoratora nie ma racji bytu

Moim zdaniem AOP to w 99% przerost formy nad treścią. Widziałem mało sensownych przypadków AOP, np. @Transactional w springu, a i to potrafi zagiąć nowych ludzi. Jeżeli potrzebujesz żeby każde wywołanie dowolnej metody regenerowało zmienną, to po prostu wywołaj to na początku każdej metody. Nie jest to super pro java EE rozwiązanie, ale jest proste, czyste, zrozumie każdy bez względu na poziom wtajemniczenia, nieprzeinżynierowane i co najważniejsze - nie sprawi Ci żadnych ukrytych problemów.

0

Dzięki za odp .. no właśnie nie chciałem tego pisać jak Ty zaproponowałeś, bo to trochę zaśmieci mi kod, niby jedna linia ale zawsze, ale tak jak twierdzisz - no jest proste.
Chciałem zastosować ewentualnie ten AspectJ.

Mówisz, że to jest przerost formy nad treścią. A np walidacja formularzy, które dostajemy z zewnątrz ? Gdzieś czytałem, że właśnie takie rzeczy powinno się robić aspektami. Więc jak to jest ?

0

Przez czysty kod rozumiem taki twór, na który patrząc przez 30 sekund wiem co robi. Jeżeli piszesz długo w np. Springu to wiesz co znaczy @PreAuthorize czy @Transactional, ale z pewnością nie wiesz co robi jakaś dziwna adnotacja którą napisał Twój kolega. Jeżeli dodatkowo pointcut jest deklarowany tak że na pierwszy rzut oka go nie widać, to jest to najgorszy syf jaki programista może napisać. Nie chodzi o to żeby pisać jak najkrócej, ale jak najczytelniej bo to właśnie na czytanie kodu poświęcisz 90% czasu. Lepiej stracić sekundę na przeczytani lini niż godziny na debugowaniu kodu który nie działa tak jak powinien bo ma w środku magię.

Jeżeli chodzi o walidację, to rozumiem że chodzi Ci o JSR303. Jest to standard i faktycznie można zaprzęgnąć do tego aspekt (choć niekoniecznie) do walidacji. Jest to jednak jeden z tych przypadków który każdy zna i każdy rozumie. Zwykle jest to jednak walidacja na bardzo prosty poziomie jak @NotNull, @NotEmpty @Max @Min etc, a bardziej poważne walidacje typu sprawdzCzyOsobaJestWBazie() powinno robić się już normalnie w kodzie serwisu.

Dam Ci radę odnośnie AOP. Jeżeli nie czujesz się uber pro programista któremu seniorzy pastują buty, nie twórz sam aspektów. Kiedy już się takim poczujesz, to zaczniesz je pisać i jestem bardziej niż pewny że się przeliczysz co do swoich umiejętności, a na Twój kod będą ludzie rzucać kurwami dopóki się projekt nie skończy. Potraktuj AOP jak morfinę. Kiedyś miała zrobić rewolucję medyczną i każdy brał ją na kaszel, a teraz używa się jej w ściśle kontrolowanych warunkach przez bardzo wykwalifikowane osoby.

0

Do tego wyżej dodam.. że aspekty to taki paradoks:

  • jak masz mało doświadczenia to aspekty są Ci potrzebne, ale nie umiesz ich robić i nawet jak coś napiszesz co działa,to finalnie walnie Cię po głowie na produkcji,
  • jak masz odpowiednio dużo doświadczenia, żeby pisać aspekty to już ich raczej nie potrzebujesz (chyba, że piszesz w Javie 1.4)

W twoim przypadku sprawa jest prosta:

Chciałbym aby to pole zostało update'owane za każdym razem gdy:

-wywołuję odpowiednią metodę tej klasy
-tworzę obiekt tej klasy
-pobieram tą obiekt tej klasy z bazy danych (ta klasa to encja).

Punkt 2 i 3 to po prostu konstruktor.
Punkt 1... no to wywołaj ten update w tej/tych metodach. To nadal mniej kodu niż pisanie aspektu i określanie gdzie będzie działać. No stary....

0

No właśnie, dobrze, że to napisałeś bo tak rozkminiałem. Przecież takie zastosowanie aspektu może wprowadzić niezłe zamieszanie no nie ? Załóżmy, że właśnie zrobiłbym z tym randomem za pomocą aspectJ. Ktoś czytając kod zastanawiałby się w jaki sposób ta wartość jest updatowana. Dopiero jakby gdzieś w projekcie znalazł mój aspekt to by ogarnął. Ale do tego czasu przypał

0

@jarekr000000:

W sumie racja, mogę zrobić bezargumentowy konstruktor który będzie wywoływał prywatną updatującą metodę podczas tworzenia tej encji i pobierania z bazy i podczas updatowania. API nie zaśmiecę no i fakt, to tylko 1 linia.

1 użytkowników online, w tym zalogowanych: 0, gości: 1