Java:在数组中存储方法调用并稍后执行?

时间:2014-06-15 22:38:55

标签: java methods abstraction

我环顾四周但却无法找到我正在寻找的东西。

我发生的事情是我定义了一个类,用于表示JPanel中的一个区域,您可以通过创建指定大小的bufferedImage来绘制它,并将该图像图形用于doubleBuffer到JPanel然后,该区域被绘制为父JPanel的图像,基本上创建了面板区域,而不必处理javax的疯狂面板组织逻辑,该逻辑取决于触摸边界的所有面板。这实际上是图形小部件的图形上下文,可以移动/调整大小等,类似于视频游戏UI。

我想要做的是我希望能够存储方法调用以在图形类中绘制操作,包括参数。这样做的目的是,无论是在运行时还是在源代码中,我都可以使用已经指定的参数值加载方法,只需调用它而不必破坏封装,因为它代表父类我必须直接绘制到bufferedimage,我想避免这样,以便可以在运行时添加方法,或者必须在PanelRegion类本身中完成绘制方法调用,迫使我每次创建一个新的专用PanelRegion想要另一个有效工作的PanelRegion。

我希望能够做的只是:

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();
}
}

如果这没有意义,基本上我发现的唯一解决方案是你可以抽象地将方法加载到带有反射器类的数组中,但是当你想要执行时你必须仍然发送值该方法的参数,基本上使它成为源代码中复杂的方法调用。我想要删除那个步骤或者做出来,这样方法就可以用我给出的值来执行。

2 个答案:

答案 0 :(得分:14)

您要做的事情称为Command Pattern

在Java中执行此操作的一种简单方法是创建一个实现Runnable的匿名类。 Runnable是一个定义单个方法的接口:void run()。您可以在代码中的任何位置实现匿名类,当您这样做时,可以引用当前范围中的任何变量。

通过为functional interfaces and lambda expression添加一些语法糖,Java 8使这变得更容易。您的问题中的代码在Java 8中将如下所示:

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

当你还没有使用Java 8时,代码有点复杂:

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

在上述两个(完全等效的)示例中,graphics.drawRectangle(xPos, yPos, width, height)未执行。它仅在调用methodCall.run()时执行。

panelRegion的实现将使用它将要执行的命令维护List<Runnable>。当它执行该列表时,它只是在每个列表上调用.run()方法。

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();
         }
    }
}

答案 1 :(得分:2)

+1 @Phillipp回答。此外,如果您有从方法返回的对象,则可以使用Callable

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

以下Java 8:

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

并调用如:

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
         }
    }
}