将方法引用传递给对象构造函数

Passing a method-reference to an objects constructor

我觉得在谈到静态类型语言时我缺少了一些东西。当我以前几乎只使用 perl 时,有很多方法可以告诉对象调用哪个函数。

现在我在 Java,我看不出如何轻松地做类似的事情

我有一个通用的 Button class。这是class所有将要使用的实际按钮的子集:每个按钮在单击时都有不同的调用方法。

真的没有办法传递对方法的引用以在单击时调用,以便我可以对所有按钮使用一个 class 吗?

目前,我创建的按钮是这样的:

// 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);

这当然包含无数子classes,每个子只在位置、label/graphics 和方法调用方面有所不同。做类似这样的事情更有意义:

// 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);

就像我说的,我觉得我一定遗漏了一些东西,因为应该有一种方法来实现这一点是有道理的,因此让我只用了一个 Button class 而没有任何 subclasses.

例如,您可以使用 Runnable:

class MyButton {
    private final Runnable action;

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

然后在单击按钮时调用 action.run()

然后在创建按钮时,可以传递一个 reference to a method,只要它具有 void return 类型,并且不带任何参数。

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

其他接口可用于不同的方法签名。

在 Java 8 中,您可以同时使用方法引用和 lambda:

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

你可以在 Java <8 中做类似的事情,但是匿名 类:

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

If that's what interfaces are for, then I must've been using them for something else than their intended purpose. I'd love to see an answer involving some code examples for this.

让你的 Buttons 实施 observer pattern, just like Swing does. Then you can even just use Swing's ActionListener interface, or even Runnable 是个不错的选择,或者例如自己滚动:

// 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.

还有无数其他方法可以实现这一点。例如,您甚至可以这样做:

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

然后让你的更高级别 UI 逻辑类似于:

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

创建按钮时:

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

或者让他们维护一个列表而不是构造函数中传递的单个对象。或其他。

为这只猫剥皮的方法无穷无尽,但希望您能在这里得到一些启发。查看 Swing 的工作原理。