Ortodoksyjny sposób na wydobycie metody z klasy?

0

Przykład w C++.

class Klasa {
   bool execute(sometype arg) {}
}

xxx = &Klasa::execute;

Czy zabawy z grupy std::bind (przypomina mi się luabind i pythin bind)

 using namespace luabind;

void greet()
{
    std::cout << "hello world!\n";
}

...
   open(L); // otwarcie silnika Lua, poza wątkiem

   module(L)
    [
        def("greet", &greet)
    ];

A teraz Java, jednak NAJBLIŻSZE moim palcom jest użycie refleksji

xxx = Klasa.class.getMethod("execute", types)

By na xxx kiedyś zostało wykonanei Invoke(zzz)

Tak, wiem, po bożemu by było wprowadzać obiekty funkcyjne, strategie czy coś podobnego

class Klasa {
 stastic class Executor {
       bool execute (Klasa kl)
   }
   public final Executor = new Executor (this); // tu warning 
 }  

Lub ten sam sens, napisany nowocześniej jako Function<T,R>

Kontekst:
wypuszczenie pewnych z tych czynności na interfejs użytkownika, np menu, i być może wykonanie tego za długi czas (nie natychmiast). Nudny program biznesowy, z wieloma, wieloma taki konstrukcjami , w tym po kilka eksportowanych metod w klasie

Dla ortodoksów, sprawa jest jeszcze gorsza. I tak bym machał refleksją, np w celu ewidencji adnotacji
czyli

class Klasa {
       @Caption("Daj podwyżkę 100 zł")
      bool execute (arg1, arg2)
 }
xxx = Klasa.class.getMethod("execute", types)
yyy = xxx.getAnnotation(Caption.class);

w oczywistym celu, by ten string przekazać do UI

Wszystkie główne sposoby wychwyciłem?
Dlaczego jestem taki niedobry, upierając się na refleksję?

Kotlin daje lepsze w tym względzie możliwości, niedostepne w Javie ? (nie mam przekonania, że chiałbym zerwac kompatybilnośc z kimś dokładającym fragmenty kodu jednak w Javie, np wdrożeniowcem)

0

Załóżmy, ze masz jakiś timer, który co kliknięcie sprawdza czy coś jest w jakimś polu, to nie trzeba tutaj żadnej refleksji (nie pakuj się w nią jeżeli da się inaczej), tylko zwykłe użycie interface'u:

private Runnable todo = new Runnable(){
  @Override
  run(){
    System.out.println("Hello World);
  }
}

public onTick(){
  todo.run();
}
0

"użytkownik niczego nie pisze z literek, tylko zostają mu przedstawione wybory, np gotowe do kliknięcia menu"
To w jakim celu ta refleksja? Dobry boze :o Nie idz ta droga... To bedzie nie utrzymywalne... Uzyj interfejsów?

0

Pewnie pięknego dnia na classpath pojawia się

package xxxx;

import Place.*;

public class Skladniki202207 {

}

public class Naliczenia202207 {
    public Naliczenia202207(Pracownik ref) {
        computeHistory2022();
    }

    void computeHistory2022(){
    }

    @Caption("Płace/Lipeic2022/Sprawdzenie")
    public String sprawdz() {
      return "K, jesteś targetem polityków, zarobiłeś XXX zł";
    }

    @Caption("Płace/Lipeic2022/Nalicz lipiec2022")
    public  Skladniki nalicz() {
        ...
    }
}
package xxxx;

import PojazdyFirmy.*;


public class ProcesorPojazdów {
    public ProcesorPojazdów(Pojazd ref) {
    }

    @Caption("Samochody/Przyjmij na ewidencję")
    public String przyjmij() {
      return "przyjęte pod nt ABC/123";
    }

    @Caption("Samochody/Tankowanie")
    public  void tankuj(float litry, BigDecimal kwota, long przebieg) {
    }
    
    @Caption("Samochody/Inne koszty")
    public  void  serwis(@Caprion("Podaj opis czynności")String opis, BigDecimal kwota, long przebieg) {
    }
     
    @Caption("Samochody/Wycofaj z ewidencji")
    public String wycofaj() {
      return "ble ble";
    }
}

Tylko tyle i aż tyle. Z designerem UI widzieliśmy się pól roku temu, i nie ma powodu dzwonić.

Adnotacje, i metody nad jakimi wiszą zostaną przeskanowane refleksją i zapamiętane w kernelu (szczegół techniczny, procesor adnotacji / SPI), podane menu ujawniają się w aplikacji (w tych miejscach, a jakim dysponujemy obiektem Pracownik / Pojazd). Jest analizowany konstruktor.

W razie użycia menu, dla takiego Naliczenia /ProcesoraPojazdów jest robione newInstance(Pracownik) itd...

Celowo drażnię się dwoma-trzema metodami, nie pasuje tu żaden wymyślony wcześniej interface, a o interface na jeden strzał mam swoje zdanie.
To implementujący funkcjonalność dziedzinową nazywa metody, a nie dziedziczy sztuczne intefejsy

Zerowa, żadna zależność klas od UI, nawet im nie świta, czy są na destopie / androidzie / webie.
Krótkie, skrajnie mały narzut kodu nie-dziedzinowego, dla programisty dziedziny, być może takiego w terenie, który bardziej jest specem dziedzinowym, niż rasowym zapleczowym.

Ja w ogóle się z Wami drażnię, nie zgadzam się że refleksja to diabelski wymysł. Ale chętnie przyjmę inne spojrzenie, ale na Boga, nie o kosztach przewyższających zyski.
Pytam o to, co w temacie: jak ładniej wyłuskać, zapamiętać i wykorzystać w przyszłości metodę.

0

Ta klasa 'Naliczenia202207' wyglada jakbys chcial zrobic obiekt z klasy i bedziesz mial nagle 100 klas NaliczeniaXXXXX rozniacych sie numerem? o.O

Jak dla mnie wymieszanie odpowiedzialnosci w ramach jednej klasy. Bo jedno to warstwa prezentacji a jedno to logika biznesowa.

0

Odpowiednikiem C++owego std::bind będzie lambda, która przyjmuje this jako pierwszy argument a reszta jest taka jak w metodzie

class Klasa {
   bool execute(sometype arg) {}
}

(Klasa k, sometype arg) -> k.execute(args)
1

Czyli masz tą swoją klasę, opisaną adnotacjami. Masz jakiś UI i chcesz, żeby dla każdej metody pojawił się na formatce guzik, który tę metodę wywoła, i będzie miał labelkę opisaną @Caption?

Jeżeli to z grubsza opisuje twój problem, to możesz:
Rozwiązać to obiektowo, ale z jakiegoś powodu nie chcesz - OK. Pewnie jakimś rozwiązaniem byłby adapter zwracający listę obiektów z metodą String caption() i execute()

Zrobić to refleksjami, skanujesz jakie są metody w podanym obiekcie, sprawdzić, które z nich mają adnotację @Caption stworzyć sobie pętlę, która dla każdej z tych metod stworzy guzik i ustawi mu metodę po refleksji. Ma to swoje ograniczenia, ale będzie działać. Zakładam, że jak metoda ma parametry, to dynamicznie stworzysz formatkę do wprowadzenia tych danych, które są potrzebne.

Ostatnia metoda jaka mi przychodzi do głowy, to skorzystanie z APT. Dalej możesz używać adnotacji, ale podczas nazwijmy to "prekompilacji" dopisujesz sobie ten adapter automatycznie. Czyli piszesz kod, który napisze kod i dopiero to wszystko zostanie skompilowane.

Jeżeli chcesz spróbować tej metody, to szukaj "APT", tu masz bibliotekę, która pomaga programować pisanie kodu: https://github.com/square/javapoet o ile pamiętam był tam jakiś przykład.
Kiedyś robiłem sobie wprawkę i jakieś tam efekty możesz zobaczyć tutaj: https://github.com/piotrpo/watchers próbowałem stworzyć, nie pamiętam już z jakimi rezultatami nie używający refleksji odpowiednik DynamicProxy Zresztą z tą klasą też się zapoznaj, bo może ci ułatwić parę spraw w podejściu z refleksjami. https://www.baeldung.com/java-dynamic-proxies

0

@piotrpo:

Dzięki za dyskusję.

Np rozmawiając z "gumową kaczuszką" utwierdziłem się np, że to są Kontrolery (w sensie MVC, MVVC) , tylko nieco inaczej powoływane do życia.
Ich zwiazek z warstwami poniżej (baza, serwisy, whatever) jest w pełni typowany i kompilowany - kłótnie tylko o wyeksportowanie tego na UI.

0

Ogólnie to jest dosyć ciekawe, bo te adnotacje w innych językach np. python są dekoracjami, czyli zwykłe wrappery i dość łatwo można mieć jakiś arr i za pomocą tych adnotacji dodawać tam elementy.
I wszystko dynamicznie się odbywa co jest znacznie prostsze.

Z javy nie korzystam, ale one są wykonywane jakby w operacji preprocesora, dodawane do rzeczywistego kodu i dopiero kompilowane, można było by dodać jakiś statyczny obiekt menu i za pomocą adnotacji dodawać do niego odpowiednie elementy, kompletnie nie wiem jak w javie, ale w pythonie to mega proste do zrobienia, chodź w javie będzie to podobnie wyglądać, czyli zwykły wrapper, który może wykonać dowolne zadanie wcześniej i później, a potem zwrócić funkcję właściwą, która jest adnotowana.

Nie miałem okazji z tego adnotacji procesora korzystać w javie raczej jak po implementujesz z dwa przykłady to lekko to ogarniesz.

0

@Szalony Programista2: W Javie adnotacje mogą pełnić bardzo różne role i istnieć na różnych etapach cyklu życia. Część z nich istnieje jedynie przed komplilacją, część również w runtime. Używanie adnotacji na etapie "prekompilacji" jest dość ciężkie i rzadko używane. Piszesz kod, który "napisze" inny kod. Można również manipulować byte codem już po kompilacji. Najczęściej używana metoda, to adnotacje widoczne runtime i sięganie do nich refleksją.
W przypadku tych ostatnich dość łatwo zrobić wrapper używając mechanizmu Dynamic Proxy (link w poprzednim poście). W skrócie, tworzysz nową klasę, do której podajesz definicję interface'u i obiekt z implementacją. Otrzymany obiekt jest pustym wrapperem, z dodatkową metodą, która jest wykonywana pomiędzy wywołaniem metody wrappera, a wywołaniem przez wrapper odpowiadającej metody na obiekcie z implementacją. Możesz sobie tam wstawić "jeżeli nazwa metody to X, to zrób coś tam jakoś tam"

0

@piotrpo:

Dynamic proxy ... ciekawe, właśnie czytam.

Coś, co jeszcze nie powiedziałem, to opóźnienie ładowania klas.
Tych kontrolerów (zestawów kontrolerów) będzie w setki, a tylko niektóre maja szanse być użyte.
Więc jakby parsowanie adnotacji było na etapie kompilacji (Procesor), zbudowana struktura na niewiele ponad stringach, nie byłoby powodu prowokować klasy do załadowania.

O tyle mam "jakieś" przemyślenia, że dawno temu skanowałem JAR-y libką ze Springa, fakt, i w sile komputerów to były inne czasy, wydajnościowo nie było to przyjemne.
Ale pomyslę i tak, i tak. Mieć z góry załadowane klasy (ciągnięte choćby przez proxy), dowiedzieć się z góry o ew wyjątkach, to tez jakaś zaleta.

0

@ZrobieDobrze: Zabawa APT (Annotation Processing Tool), jest trudniejsza i bardziej upierdliwa niż refleksje, dlatego też raczej mało popularna. Z mojej perspektywy daje za to znacznie lepsze efekty, bo refleksje to jednak takie płynięcie w poprzek nurtu języka. Da się też to normalnie debugować, bo możesz się przeklikać do tego wygenerowanego kodu, postawić tam breakpointa itd.

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