2014-06-15 16 views
7

Rozejrzałem się, ale nie mogę znaleźć dokładnie tego, czego szukam.Java: wywołać metody wywołania w tablicy i wykonać później?

To, co mam na sobie to, że mam zdefiniowaną klasę, która ma reprezentować region w JPanelu, który można narysować, aby to zrobić, tworząc buforowany obraz o określonym rozmiarze i używa tej grafiki graficznej do podwójnego bufora do JPanel, a region ten jest następnie rysowany jako obraz dla rodzica JPanel, zasadniczo tworząc regiony paneli bez konieczności radzenia sobie z szaloną logiką organizacyjną panelu javax, która zależy od wszystkich paneli dotykających granice. Jest to w zasadzie kontekst graficzny dla widżetów graficznych, które można przenosić/zmieniać rozmiar itp., Podobnie jak w interfejsie gier wideo.

Co próbuję zrobić, chcę móc przechowywać wywołania metod do operacji rysowania w klasie graficznej, parametry zawarte. Ma to na celu umożliwienie, zarówno w środowisku uruchomieniowym, jak i w kodzie źródłowym, wczytania metod z już podanymi wartościami parametrów, które mogą być wywołane bez konieczności przerywania enkapsulacji, ponieważ w tej formie albo klasa nadrzędna musi narysować bezpośrednio do zbuforowanego obrazu, czegoś, czego chciałbym uniknąć, aby można było dodawać metody w środowisku wykonawczym lub wywoływać metody dla rysowania w samej klasie PanelRegion, zmuszając mnie do stworzenia nowego wyspecjalizowanego elementu PanelRegion za każdym razem, gdy chcę innego panelu PanelRegion, które po prostu nie będą działać efektywnie.

Co chciałbym być w stanie zrobić, to po prostu coś w rodzaju:

Class graphics = panelRegion.getGraphics(); 
String methodName = "drawRectangle"; 
int xPos = 0; 
int yPos = 0; 
int width = 0; 
int height = 0; 

ImaginaryMethodClass method = graphics.getMethod(methodName, int, int, int, int); 
method.imaginaryMethodThatLoadsParameterValues(xPos, yPos, width, height); 

panelRegion.addMethod(method); 
panelRegion.invokeDrawMethods(); 

public void invokeDrawMethods() 
{ 
for(ImaginaryMethodClass aMethod : listOfMethods) 
{ 
aMethod.imaginaryMethodThatExecutesTheMethodWithTheLoadedParameterValues(); 
} 
} 

jeśli nie jest to bez sensu, w istocie jedynym rozwiązaniem Znalazłem to można abstrakcyjnie ładuj metody do tablic z klasą reflektora, jednak gdy chcesz wykonać, musisz nadal wysyłać wartości parametrów tej metody, zasadniczo czyniąc to skomplikowanym wywołaniem metody w kodzie źródłowym. Chcę albo wyciąć ten krok, albo zrobić tak, aby metoda mogła wykonać się z wartościami, które podałem.

+1

patrz [Wzór polecenia] (http://en.wikipedia.org/wiki/Command_pattern) – Bohemian

Odpowiedz

10

Co próbujesz zrobić, nazywa się Command Pattern.

Prostym sposobem zrobienia tego w Javie jest utworzenie anonimowej klasy, która implementuje Runnable. Runnable to interfejs definiujący pojedynczą metodę: void run(). Możesz zaimplementować anonimową klasę w dowolnym miejscu kodu, a kiedy to zrobisz, możesz odwoływać się do dowolnej zmiennej w bieżącym zakresie.

Java 8 czyni to o wiele łatwiejszym poprzez dodanie cukru syntaktycznego do functional interfaces and lambda expression. Kod w swoim pytaniu będzie wyglądać w Java 8:

Graphics graphics = panelRegion.getGraphics(); 

Runnable methodCall =() -> graphics.drawRectangle(xPos, yPos, width, height); 

panelRegion.addMethod(methodCall); 

Kiedy nie używać Java 8 Jeszcze kod jest nieco bardziej zawiła:

Graphics graphics = panelRegion.getGraphics(); 

Runnable methodCall = new Runnable() { 
    public void run() { 
     graphics.drawRectangle(xPos, yPos, width, height); 
    } 
} 

panelRegion.addMethod(methodCall); 

w obu (całkowicie równoważne) przykłady powyżej, graphics.drawRectangle(xPos, yPos, width, height) nie jest wykonywany. Jest wykonywany tylko po wywołaniu methodCall.run().

Implementacja paneluRegion zachowałaby numer List<Runnable> za pomocą poleceń, które zamierza wykonać. Kiedy wykonuje tę listę, po prostu wywołuje metodę .run() na każdym z nich.

class PanelRegion { 

    private List<Runnable> listOfMethods = new ArrayList<>(); 

    public void addMethod(Runnable methodCall) { 
     listOfMethods.add(methodCall); 
    } 

    public void invokeDrawMethods() 
    { 
     for(Runnable aMethod : listOfMethods) { 
      aMethod.run(); 
     } 
    } 
} 
+0

Dziękujemy za dodanie działającego bitu; Już sprawdziłem strukturę poleceń na wikipedii i chociaż zadziałało, miałem pewne problemy. To działało dużo łatwiej i bardziej niezawodnie – user3743139

1

+1 za odpowiedź @Phillipp. Dodatkowo, jeśli masz obiekt do zwrotu ze swojej metody, możesz użyć Callable.

Graphics graphics = panelRegion.getGraphics(); 

Callable methodCall =() -> graphics.drawRectangle(xPos, yPos, width, height); 

panelRegion.addMethod(methodCall); 

Na poniższym Java 8:

Graphics graphics = panelRegion.getGraphics(); 

Callable methodCall = new Callable() { 
    @Override 
    public Object call() { 
     return graphics.drawRectangle(xPos, yPos, width, height); 
    } 
} 

panelRegion.addMethod(methodCall); 

i wywołać tak:

class PanelRegion { 
    private List<Callable> listOfMethods = new ArrayList<>(); 

    public void addMethod(Callable methodCall) { 
     listOfMethods.add(methodCall); 
    } 

    public void invokeDrawMethods() 
    { 
     for(Callable aMethod : listOfMethods) { 
      Object ret = aMethod.call(); 
      // do something with ret 
     } 
    } 
}