简体   繁体   中英

I'm new to java from a javascript background: how do they manage event listeners properly and not tighting classes together?

I've been trying to do some "simple thing" in java that in javascript would look like:

// Main class
var model = new Model();
this.callback = function(e){/* do something */}
model.addListener("change", callback);

Well in java what I found so far is making the Main class deriving from java.util.Observer and Model from java.util.Observable; Then when the model will dispatch the event it will call the update method on the Main class. I found really ugly and not elegant at all. I can't even think of how I could work with this;

Is there any cleaner and flexible ways, maybe some libs to help me out here, because I have not found any acceptable tutorial about how to do it like this?

thanks a lot

Well what I've managed so far, and I quite I like it a lot more than creating "empty" classes just for simple events (but still not good, at least for me):

private ArrayList __items;
public void addListener(Method method, Object object){
    this.__listeners.add(new Object[] {method, object});
}


public void dispatch(){
    int i = this.__listeners.size();
    Method method;
    Object context;
    while(i>0){
        i--;
        method = (Method)(this.__listeners.get(i))[0];
        context = (Object)(this.__listeners.get(i))[1];
        try{
            method.invoke(context);
        }catch(java.lang.reflect.InvocationTargetException e){

        }catch(java.lang.IllegalAccessException e){

        }
    }
}

Then I use like this:

Gifts gifts = prendastotty.PrendasTotty.getMain().getLoggedUserGifts();
Class[] parameterTypes = new Class[0];
try{
    Method m = Home.class.getMethod("__updateTable", parameterTypes);
    gifts.addListener(m, this);
}catch(NoSuchMethodException e){

}

It this leaky/anti-pattern/buggy?

I must say that I had a bit of trouble keeping up with your code because in my head some of the stuff didn't make sense (from a Java way of thinking, or at least my Java way of thinking). So I hope I understood you correctly and can help you out.

Let's first take your simple example:

var model = new Model();
this.callback = function(e){/* do something */}
model.addListener("change", callback);

In Java a good approach,for example, would be:

public interface ModelListener {
   public void execute(Model context);
}

public class Model { 
    private List<ModelListener> listeners;

    public Model() {
      this.listeners = new ArrayList<ModelListener>();
    }

    public void addListener(ModelListener listener) {
      this.listeners.add(listener);
    }

    public void dispatch() {
      for (ModelListener listener: listeners) {
        listener.execute(this);
      }
    }

}

With this sort of design you can now do one of two things:

Use anonymous classes

In Java the most common case is that all your classes have a name, although there are cases when you can create anonymous classes, these are basically classes that are implemented inline. Since they are implemented inline, they're usually only used when they're small and it's known they won't be re-usable.

Example:

Model model = new Model();
model.add(new ModelListener() {
     public void execute(Model model) { /* do something here */ }
});

Notice how the new ModelListener object is created (which is an interface) and the execute implementation is provided inline. That is the anonymous class.

Interface Implementations

You can create classes that implement your interface and use them instead of anonymous classes. This approach is often use when you want your listeners to be re-usable, have names that give semantic meaning to the code and/or they're logic isn't just a few lines of code.

Example:

public class LogListener implements ModelListener {

 public void execute(Model model) {
   // Do my logging here
 }
}

Model model = new Model();  
model.addListener(new LogListener());

Side note

As a side note, I saw that the method you were trying to bind as a listener was called __updateTable are you by any chance trying to detect object's changes so you can commit them to the database? If so I strongly suggest you to look at some ORM frameworks such as Hibernate or JPA they'll keep all that hassle from you, keeping track of changes and committing them to the database.

Hope it helps, regards from a fellow portuguese StackOverflow user ;)

You will find it a bit difficult to try to directly map javascript ideology into java. Their underlying philosophies are different. Without more definite code and expectations it is difficult to give you a clearer answer. Here is a sample of code in GWT (written in java ) that attaches a click handler to a button.

Hope this helps you get started.

 myButton.addSelectionListener(new SelectionListener<ComponentEvent>(){
                @Override
                public void componentSelected(ComponentEvent ce) {
                    // do your processing here                          

                }

            });

In Java, a function can't exist outside of a class as it can in Javascript. So when you need to provide a function implementation at runtime, you have to wrap that function inside a class and pass an instance of the class, unfortunately.

The solution you have using reflection will work (I assume), but it is not the preferred way to do it in Java since what used to be compile-time errors will now be runtime errors.

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