简体   繁体   中英

The correct way to pass a function as a string

Please allow me to explain what I am trying to do - I think that the title explains it roughly, but I am none too sure that I am going about things the right way, so please correct me if I am wrong!

I have created a custom dialog using a LayeredPane . Essentially a jPanel is shown on the POPUP_LAYER , thus appearing over the top of the main content. This panel contains a simple 'label-textbox-okay-cancel' group of controls. I will call this the 'Dialog Panel'.

What am I trying to do: When a button is clicked on the main window (contained within the LayeredPane ), the Dialog Panel will appear and allow the user to enter some text, then click okay or cancel. This is all easy enough, but I would like this code to be re-usable, which means that other buttons on the main window will invoke the same Dialog Panel , but with different text in the label.

This of course requires me to include some kind of callback function so that the okay button on the Dialog Panel will run the correct code, according to the button which invoked it.

My current attempt is to store a string which will contain the name of the function that should be run when the user clicks the okay button on the Dialog Panel . I am attempting to retrieve this string and convert it into the function name and so far I have found many references to 'Reflection', many of them suggesting that it is not a good idea.

In any case I have been unable to get any example code to work because I do not understand what the 'obj' is in the code below and am unable to invoke the method:

method = obj.getClass().getMethod(myCallbackString);

My questions are:

Firstly, am I even going about this the right way? I am more than open to suggestions, but please try to keep it as simple as possible because I really am just getting started!

Secondly, what is the 'obj' in the code shown above? I would really like to know, even if this is not the way that I should be doing things!

My other thoughts include: Should my Dialog Panel be in its own class, and if so, again, how to pass the callback function?

Any help or advice would be gratefully received.

BTW: In answer to the question "why not use a normal dialog?" I can only say that I am currently experimenting, and I simply want to see if I can do this!

MVK

The usual way the callback functions are passed in by Java programs is by passing instances of interfaces that implement a specific callback function. It is typical, though not required, to implement the interface anonymously.

For example, here is an interface:

interface MyCallback {
    void performCallback();
}

Here is the way you define your dialog's method that takes a callback:

void openWithCallback(MyCallback cb) {
    // Do something useful...
    ...
    // Perform the callback
    cb.performCallback();
}

Here is the way that you invoke that method:

public void OpenDialog() {
    myDialog.openWithCallback(new MyCallback() {
        public void performCallback() {
            System.out.println("Inside callback...");
        }
    });
}

obj names the object whose method you want to call, in your case you can probably replace it with this (or drop it out entirely, since this is implied):

private void callByName(String name) { 
  try { getClass().getMethod(name).invoke(this); }
  catch (RuntimeException e) { throw e; }
  catch (Exception e) { throw new RuntimeException(e); }
}

For this to work you need to declare a public no-arg method with the appropriate name.

  1. I think your idea is valid, although it has a major drawback: you store the method names as simple strings in your code, so the compiler can't check them for validity. Therefore, if you change the name of a method, you manually have to make sure you have updated all the strings referencing it. This is what's usually meant with 'reflection is a bad idea'.
  2. obj in your code is the object on which you want to call a method. As a simple example, the equivalent of someInteger.toString(); with reflection would be someInteger.getClass().getMethod("toString").invoke(); .

On a more generic note, once you're comfortable with Java, you might also check out a functional language like Scala, where functions are regular objects, and the scenario you intend could be implemented with full compiler checking.

I think that you're making this way more complicated than it has to be. You said you want this:

This is all easy enough, but I would like this code to be re-usable, which means 
that other buttons on the main window will invoke the same Dialog Panel, but with
different text in the label.

A DialogBox is, by definition, reusable. Why don't you just have the button click listener pass the appropriate text to the dialog box when clicked, so it shows the correct information?

If you need specific actions to happen after a button click on the dialog depending on the invoker, you may want to consider:

  1. Created a custom DialogBox extension that includes logic that knows what to do based on who called it. Then when a button invokes the custom dialog, it would pass it a parameter to let it know what it wants to do after the dialog box is dismissed.

  2. Look into using something like the abstract factory pattern.

Yes, you could do this via reflection. Yes, it would be a very bad idea, for many reasons that other people have discussed in other answers, especially if this is production code (though you seem to indicate it's an experiment.)

If you really just want to see how to work it with reflection, you'll probably want to read up on that topic. I found this to be one of the better tutorials out there.

I haven't worked with JPanel, but what I understand form your query, answer seems rather simple. Instead of passing method name, why dont you work on interface and pass the different implementation of that interface?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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