简体   繁体   English

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

[英]Java: store method calls in an array and execute later?

I've looked around but can't find exactly what I'm looking for. 我环顾四周但却找不到我想要的东西。

What I have going on is I have a class defined that is meant to represent a region in a JPanel that you can draw to which it does by creating a bufferedImage of the specified size and uses that images graphics to doubleBuffer to the JPanel, and that region is then drawn as an image to the parent JPanel, essentially creating panel regions without having to deal with javax's crazy panel organizing logic that depends on all panels touching boarders. 我发生的事情是我有一个定义的类,用于表示JPanel中的一个区域,你可以通过创建一个指定大小的bufferedImage来绘制它,并将图像图形用于doubleBuffer到JPanel,然后将区域作为图像绘制到父JPanel,基本上创建面板区域而不必处理javax的疯狂面板组织逻辑,该逻辑取决于触摸边界的所有面板。 This is essentially a graphics context for graphics widgets that can move/resize etc, similar to video game UI. 这实际上是图形小部件的图形上下文,可以移动/调整大小等,类似于视频游戏UI。

What I'm trying to do is I want to be able to store method calls to draw operations in the graphics class, parameters included. 我想要做的是我希望能够存储方法调用来绘制图形类中的操作,包括参数。 The purpose for this is so that I can, either at runtime or in source code, load in methods with the parameter's values already specified that can just be called without having to break encapsulation, because as it stands either the parent class has to draw directly to the bufferedimage, something I would like to avoid so that methods can be added at runtime, or the method calls for drawing have to be done in the PanelRegion class itself, forcing me to create a new specialized PanelRegion every time I want another PanelRegion, which just won't work effeciently. 这样做的目的是,无论是在运行时还是在源代码中,我都可以使用已经指定的参数值来加载方法,只需调用它而不必破坏封装,因为它代表父类必须直接绘制对于bufferedimage,我想避免一些事情,以便可以在运行时添加方法,或者必须在PanelRegion类本身中完成绘制方法调用,迫使我每次想要另一个PanelRegion时创建一个新的专用PanelRegion,这将无法有效地工作。

What I would like to be able to do is simply something like: 我希望能做的只是:

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

If this isn't making sense, essentially the only solution I've found is you can abstractly load methods into arrays with the reflector class, however when you want to execute you have to still send the values for the parameters of that method, essentially making it a complicated method call in source code. 如果这没有意义,基本上我发现的唯一解决方案是你可以抽象地将方法加载到带有反射器类的数组中,但是当你想要执行时你必须仍然发送该方法的参数的值,本质上使它成为一个复杂的方法调用源代码。 I want to either cut that step out or make it so the method can execute itself with the values I've given. 我想要切出那个步骤或者做出来让方法可以用我给出的值来执行。

What you are trying to do is called the Command Pattern . 你要做的是称为命令模式

A simple way to do this in Java is to create an anonymous class which implements Runnable . 在Java中执行此操作的一种简单方法是创建一个实现Runnable的匿名类。 Runnable is an interface which defines a single method: void run() . Runnable是一个定义单个方法的接口: void run() You can implement an anonymous class anywhere in your code, and when you do, you can reference any variable in the current scope. 您可以在代码中的任何位置实现匿名类,并且在执行时,可以引用当前范围中的任何变量。

Java 8 makes this a lot easier by adding some syntactic sugar for functional interfaces and lambda expression . 通过为函数接口和lambda表达式添加一些语法糖,Java 8使这变得更容易。 The code in your question would look like this in Java 8: 您的问题中的代码在Java 8中将如下所示:

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

When you don't use Java 8 yet, the code is a bit more convoluted: 当你还没有使用Java 8时,代码有点复杂:

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

In both of the (completely equivalent) examples above, graphics.drawRectangle(xPos, yPos, width, height) is not executed. 在上面的两个(完全等效的)示例中,不执行graphics.drawRectangle(xPos, yPos, width, height) It is only executed when methodCall.run() is called. 它仅在methodCall.run()时执行。

The implementation of panelRegion would maintain a List<Runnable> with the commands it is going to execute. panelRegion的实现将使用它将要执行的命令维护List<Runnable> When it executes that list, it just calls the .run() method on each of them. 当它执行该列表时,它只调用每个列表上的.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 for @Phillipp answer. +1为@Phillipp回答。 Additionally, if you have object to return from your method, you can use Callable . 此外,如果您有从方法返回的对象,则可以使用Callable

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

For below Java 8: 对于Java 8以下:

Graphics graphics = panelRegion.getGraphics();

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

panelRegion.addMethod(methodCall);

And Invoke like: 并调用如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM