Re: Delegates...?



Gav wrote:
I am trying to write an application using the "Presenter First"
methodology that I use when coding in C# but am a bit unsure how to get
round the fact that Java does not have delegates.

I think I see what you are trying to do here, even though I'm not familiar with C#. Here is a simple example which does what you want (I think). I skipped trying to implement a list of listeners because I wanted to emphasize the "delegate" concept. Note how I use the interface called "Delegate" to make a method than can be called by the Presenter. The Presenter knows this because it is passed objects of type "Delegate".

package presenterfirst;

public class Main {
public static void main(String[] args) {
Delegate m = new Model();
Delegate v = new View();
Presenter p = new Presenter( m, v);
p.testMethod();
p.testMethod2();
}
}

interface Delegate {
void doIt();
}

class Model implements Delegate{
private int state;
public void doIt() {
System.out.println("Do something with state here");
}
}

class View implements Delegate {
public void doIt() {
System.out.println("Do something with the view here");
}
}

class Presenter {
private Delegate model;
private Delegate view;
public Presenter(Delegate model, Delegate view) {
this.model = model;
this.view = view;
}
public void testMethod(){
model.doIt();
}
public void testMethod2() {
view.doIt();
}
}

But in real Java programs, you should try to use the existing APIs.

For example, most usable Swing components support a method "addActionListener" which binds a listener to the component. The usual method is to declare the listener as an anonymous class which takes the place of your Delegate. You can use removeActionListener to remove a previously added listener, and there are methods to manipulate the listeners in other ways.

This is a very simple example. The class I make, MyFrame, is completely self contained. It gets created and it goes all by itself. It therefor contains it's own model and delegate/presenter. This is ok for very small, simple GUI components.

One thing: Swing components must be created with the pattern I use in "createGui()". They are prone to deadlock if not. It's a simple rule, see the tutorials.

Something like this:

package javamvcexample;

/**
* MVC Example
*/
public class MvcEx {
public static void main(String[] args) {
createGui();
}
private static void createGui() {
java.awt.EventQueue.invokeLater( new Runnable() {
public void run() {
new MyFrame("MVC Example").setVisible( true );
}
} );
}
}

class MyFrame extends javax.swing.JFrame {
private javax.swing.JButton myButton;
private int count;
public MyFrame( String title ) {
super( title );
myButton = new javax.swing.JButton("Click Me");
setDefaultCloseOperation(
javax.swing.WindowConstants.EXIT_ON_CLOSE);
myButton.addActionListener(
new java.awt.event.ActionListener()
{
public void actionPerformed(
java.awt.event.ActionEvent e) {
count++;
System.out.println("The count is: " + count );
}
});
this.add( myButton );
this.pack();
this.setLocationRelativeTo( null );
}
}


Ok I don't pretend to really understand your Presenter First model. But if I had to translate the example above into something like what you showed, I'd do this:

package javamvcexample2;

import java.awt.event.ActionEvent;

/**
* MVC Example2
*/
public class MvcEx {
public static void main(String[] args) {
createGui();
}
private static void createGui() {
java.awt.EventQueue.invokeLater( new Runnable() {
public void run() {
MyFrame frame = new MyFrame("MVC Example");
frame.setText( "Click Me!");
frame.setLocationRelativeTo( null );
frame.pack();
MyModel model = new MyModel();
MyPresenter presenter =
new MyPresenter( frame, model );
frame.setVisible( true );
}
} );
}
}

interface SimplePresenterView {
void setActionListener(
java.awt.event.ActionListener act );
}

class MyFrame extends javax.swing.JFrame
implements SimplePresenterView {
private javax.swing.JButton myButton;
public MyFrame( String title ) {
super( title );
myButton = new javax.swing.JButton();

setDefaultCloseOperation(
javax.swing.WindowConstants.EXIT_ON_CLOSE);
this.add( myButton );
}
public void setActionListener(
java.awt.event.ActionListener act ) {
myButton.addActionListener( act );
}
void setText( String t ) {
myButton.setText(t);
}
}

interface SimplePresenterModel {
public void doIt();
}

class MyModel implements SimplePresenterModel {
private int count;
public void doIt() {
count++;
System.out.println("The count is: " + count);
}
}

class MyPresenter {
private SimplePresenterView view;
private final SimplePresenterModel model;
public MyPresenter(SimplePresenterView view,
final SimplePresenterModel model) {
this.view = view;
this.model = model;
this.view.setActionListener(
new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
model.doIt();
}
});
}
}

Now the View is totally dumb. It has no idea where it's methods will go. The Model does the same thing as before: it keeps count of the number of clicks on the button and prints them out to the console.

There's a few hokey things about MyPresenter. I didn't like having to use the passed parameter model instead of the instance variable, but it saved me save me a few lines and both the passed parameter and the instance variable are final, so it should be ok. Keep an eye on that for your own programs though.

MyFrame implements SimplePresenterView, so the presenter can act on it and set a listener. MyModel implements SimplePresenterModel, again so the Presenter has a doIt method to use in the listener. This Presenter can bind any two classes that implement these interfaces. A more sophisticated Presenter might need to know how to bind a view that requires more than one listener to the appropriate models.


I hope I didn't booger up anything too badly in the examples above. Questions? Ask!
.



Relevant Pages

  • Re: Delegates...?
    ... Buried in that article is actually an example of how a behavior similar to delegates in C# can be implemented in Java. ... I don't really know that this is the _best_ way, but it is how I've been dealing with the lack of delegate types, and the article Lew posted appears to suggest that's in fact how the Java designers expect you deal with it. ... private event EventDelegate Test; ... public void SubscribeTestEvent ...
    (comp.lang.java.programmer)
  • C# callback from native code
    ... When you pass a delegate as a parameter, or pass a delegate contained as a field in a structure, it remains uncollected for the duration of the call. ... So, as is the case in the following enumeration example, the callback function completes its work before the call returns and requires no additional action by the managed caller. ... private SomeClass m_SomeClass; ... public void MyCallbackFunc ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Global cache in Win Apps
    ... > I have to make a global cache in a windows application to store few ... will run the delegate. ... public void SetData ...
    (microsoft.public.dotnet.framework)
  • Re: Generic Delegate Meltdown From Constraint
    ... I think that using a delegate is just making the code more difficult to implement, and it will likely make the code harder to understand later. ... public MyOwned(UnsubscribeDelegate unsubscribe) ... public void MakeOwned() ... // that an actual type is supplied for the generic type ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: When is an event null?
    ... public delegate void MyEventHandler; ... MyEvent(); // NullReferenceException? ... The event will be null until an event handler is actually added to it. ... public void add_MyEvent ...
    (microsoft.public.dotnet.languages.csharp)