2016-08-27 1 views
0

Je sens qu'il me manque quelque chose quand il s'agit de langages statiquement typés. Quand je n'utilisais presque que perl, il y avait plusieurs façons de dire à un objet quelle fonction appeler.Passer une référence de méthode à un constructeur d'objets

Maintenant que je suis en Java, je ne vois pas comment je peux faire quelque chose de similaire dans un fasion facile

J'ai une classe Button générique. Ceci est sous-classé par tous les boutons réels qui seront utilisés: Chacun avec une méthode différente à appeler lorsqu'on clique dessus.

Est-ce qu'il n'y a vraiment aucun moyen de passer une référence à une méthode à appeler lorsqu'on clique dessus, de sorte que je puisse utiliser une classe pour tous les boutons?

À l'heure actuelle, je crée des boutons comme ceci:

// Specifically using the subclass that sets "firemode" to "close" 
FiremodeClose fc = new FiremodeClose(Settings.ui_panel_start, Settings.ui_panel_row_firemode, game); 
painter.addSelectionButton(fc); 
clickTracker.addSelectionButton(fc); 

Cette ofcourse couses une myriade de sous-classes, chacun différant seulement dans le placement, l'étiquette/graphiques et appel de méthode. Il est plus logique de faire quelque chose de similaire à ceci:

// Generic button, the method that sets "firemode" is somehow passed as arguement to the contsructor. 
Button fc = new Button(&referenceToFunctionToCallWhenClicked, otherArguementsEtc); 
painter.addSelectionButton(fc); 
clickTracker.addSelectionButton(fc); 

Comme je l'ai dit, je sens que je dois manquer quelque chose, car il est logique qu'il devrait y avoir un moyen d'y parvenir, ainsi me laisser s'en tirer une seule classe Button sans aucune sous-classe.

+2

C'est à quoi sert une interface. Java 8 et Groovy implémentent des implémentations d'interface en ligne pour des cas d'utilisation comme celui-ci. – chrylis

+0

^^^ Cela, et voir aussi les classes anonymes. –

+0

@chrylis Si c'est ce que sont les interfaces, alors je dois les utiliser pour autre chose que leur but. J'aimerais voir une réponse impliquant des exemples de code pour cela. – Jarmund

Répondre

1

Si c'est ce que sont les interfaces, alors je dois les utiliser pour autre chose que leur but. J'aimerais voir une réponse impliquant des exemples de code pour cela.

Demandez à votre Buttons mettre en œuvre le observer pattern, tout comme Swing does. Ensuite, vous pouvez même simplement utiliser l'interface ActionListener de Swing, ou même Runnable n'est pas un mauvais choix, ou par exemple. rouler le vôtre:

// Your interface. 
public interface MyButtonListener { 
    public void buttonClicked(); 
} 

// Somewhere else: 
Button fc = ...; 
fc.addButtonListener(new MyButtonListener() { 
    @Override public void buttonClicked() { 
     // do stuff here 
    } 
}); 

// And in your Button have it simply iterate through all of its registered 
// MyButtonListeners and call their buttonClicked() methods. 

Il existe d'innombrables façons de l'implémenter.Par exemple, vous pouvez même faire quelque chose comme:

public interface ThingThatCaresAboutButtons { 
    public void buttonClicked (Button button); 
} 

Faites ensuite votre logique de l'interface utilisateur de niveau supérieur quelque chose comme:

public class MyUI implements ThingThatCaresAboutButtons { 
    @Override public void buttonClicked (Button button) { 
     if (button == theOneButton) { 
      // do whatever 
     } else if (button == theOtherButton) { 
      // do whatever 
     } 
    } 
} 

Et lors de la création des boutons:

theOneButton = new Button(theUI, ...); 
theOtherButton = new Button(theUI, ...); 

ou faire maintenir une liste au lieu d'un seul objet passé dans le constructeur. Ou peu importe.

Des façons infinies de peler ce chat, mais j'espère que vous avez de l'inspiration ici. Découvrez comment fonctionne Swing.

1

Vous pouvez par exemple utiliser Runnable:

class MyButton { 
    private final Runnable action; 

    public MyButton(Runnable action) { 
     this.action = action; 
    } 
    ... 
} 

Et puis appelez action.run() lorsque le bouton est cliqué.

Ensuite, lors de la création d'un bouton, vous pouvez passer un reference to a method, tant qu'il a le type de retour void, et ne prend aucun argument.

Button fc = new Button(EnclosingClass::methodToCall, otherArguementsEtc); 

D'autres interfaces peuvent être utilisées pour différentes signatures de méthode.

1

En Java 8, vous pouvez utiliser les deux références de méthode et lambdas:

class Button { 
    Button(Runnable function) { 
    } 
} 
Button b1 = new Button(() -> System.out.println("works!")); 
Button b2 = new Button(System::gc); 

Vous pouvez faire des choses similaires en Java < 8, mais il est plus bavard avec les classes anonymes:

Button b3 = new Button(new Runnable() { 
    @Override 
    public void run() { 
     System.out.println("works!"); 
    } 
});