ashes999
ashes999

Reputation: 10163

Java Equivalent to C#'s Delegates/Events: Changing Event Invoked Code Dynamically

I have a simple Screen class in C# that has a bunch of events (with corresponding delegates) like the FadeOutEvent.

I want to port my library to Java, and I find that the mechanism for events/delegates is really cludgey. Specifically, I cannot easily write code like:

if (someVar == someVal) {
  this.FadeOutComplete += () => {
    this.ShowScreen(new SomeScreen());
  };
} else {
  this.FadeOutComplete += () => {
    this.ShowScreen(new SomeOtherScreen());
  };
}

For all you Java-only guys, essentially, what I'm whinging about is the inability to reassign the event-handling method in the current class to something else dynamically, without creating new classes; it seems that if I use interfaces, the current class must implement the interface, and I can't change the code called later.

In C#, it's common that you have code that:

Strategy pattern can solve this (and does), albeit that I need extra classes and interfaces to do it; in C#, it's just a delcarative event/delegate and I'm done.

Is there a way to do this without inner/anonymous classes?

Edit: I just saw this SO question, which might help.

Upvotes: 4

Views: 13275

Answers (2)

Orwellophile
Orwellophile

Reputation: 13953

With lambdas in JDK 1.8 / Java 8:

private Runnable delegate;
public void delegateTest()  {

// ...
   this.addActionListener(e -> delegate.run());
   
// ...
   if (someVar == someVal) {
      this.delegate = () -> showSomeScreen();
   }
   else {
      // or like this:
      this.delegate = this::showSomeOtherScreen;
   }
}

private void showSomeOtherScreen() {
}

private void showSomeScreen() {
}

Upvotes: 1

JB Nizet
JB Nizet

Reputation: 691943

Most of the time, it's done the other way round:

this.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        if (someVar == someVal) {
            showSomeScreen();
        }
        else {
            showSomeOtherScreen();
        }
    }
});

But you could do something similar to your C# code by delegating to two other objects:

private Runnable delegate;

// ...
this.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        delegate.run();
    }
});

// ...
if (someVar == someVal) {
    this.delegate = new Runnable() {
        @Override
        public void run() {
            showSomeScreen();
        }
    };
}
else {
    this.delegate = new Runnable() {
        @Override
        public void run() {
            showSomeOtherScreen();
        }
    };
}

Delegates were proposed by Microsoft for Java a long long time ago, and were refused by Sun. I don't remember if anonymous inner classes already existed at that time or if they were chosen as the alternative.

Upvotes: 13

Related Questions