Delegates...?

G

Gav

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.

In C# I would create a Model class which has the actual application
functions in it, a view class which is a dumb GUI and then have a
presenter class which binds the two together. The presenters constructor
takes references to the model and view then calls methods in the model and
view classes to point a delegate to the method in the presenter. So
basically the presenter knows about the model and view but the model and
view simply fire events which call methods in the presenter.

If anybody could enlighten me here it would be great, its years since I've
done any Java and I'm just trying to get back into it. I've included some
example C# code which probably explains better what I'm trying to do.

thanks

Gav


public delegate void EventDelegate();

public class Model
{
private event EventDelegate Test;

public Model()
{
}

pivate void CallTest()
{
if ( this.Test != null )
this.Test();
}

public void SubscribeTestEvent(EventDelegate listener)
{
this.Test += listener;
}
}


public class View
{
private event EventDelegate Test2;

public View()
{
}

private void CallTest2()
{
if ( this.Test2 != null )
this.Test2();
}

public void SubscribeTest2Event(EventDelegate listener)
{
this.Test2 += listener;
}

}

public class Presenter
{
private Model myModel;
private View myView;

public Presenter(Model pModel, View pView)
{
this.myModel = pModel;
this.myView = pView;

this.myModel.SubscribeTestEvent(TestMethod);
this.myView.SubscribeTest2Event(TestMethod2);
}


private void TestMethod()
{
// Do Something
}

private void TestMethod2()
{
// Do Something
}
}
 
P

Peter Duniho

[...]
If anybody could enlighten me here it would be great, its years since
I've
done any Java and I'm just trying to get back into it. I've included some
example C# code which probably explains better what I'm trying to do.

I see that Lew has posted a link to a good example of the human capacity
for rationalization. Buried in that article is actually an example of how
a behavior similar to delegates in C# can be implemented in Java.
Unfortunately Lew didn't bother to point out where the useful information
was amongst all that chaff.

Anyway, basically Java doesn't have delegates or anything like that.
Instead, you can use interfaces to accomplish similar behavior. 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.

So instead of declaring a delegate type, you declare an interface that
includes a method representing the signature you want to call back. Then
you implement the interface (in your main class, in an inner/nested class
that you can instantiate as needed, or using an anonymous inner class) and
provide an instance of that implementation to whatever needs it.

In that way, your code might become something like this (quoting your
original code, adding replacement lines as necessary...I think this is a
clear way to represent the changes, but if not please don't hesitate to
ask for clarification; also, see notes at the end):
public delegate void EventDelegate();

public interface EventDelegate
{
public void Execute();
}
public class Model
{
private event EventDelegate Test;

private ArrayList said:
public Model()
{
}

private void CallTest()
{
if ( this.Test != null )
this.Test();

for (EventDelegate delegate : this.Test)
{
delegate.Execute();
}
}

public void SubscribeTestEvent(EventDelegate listener)
{
this.Test += listener;

this.Test.add(listener);
}
}


public class View
{
private event EventDelegate Test2;

private ArrayList<EventDelegate> Test2 = new
ArrayList said:
public View()
{
}

private void CallTest2()
{
if ( this.Test2 != null )
this.Test2();

for (EventDelegate delegate : Test2)
{
delegate.Execute();
}
}

public void SubscribeTest2Event(EventDelegate listener)
{
this.Test2 += listener;

this.Test.add(listener);
}

}

public class Presenter
{
private Model myModel;
private View myView;

public Presenter(Model pModel, View pView)
{
this.myModel = pModel;
this.myView = pView;

this.myModel.SubscribeTestEvent(TestMethod);

this.myModel.SubscribeTestEvent(new EventDelegate() { public void
Execute() { TestMethod(); } });
this.myView.SubscribeTest2Event(TestMethod2);

this.myView.SubscribeTest2Event(new EventDelegate() { public void
Execute() { TestMethod2(); } });
}


private void TestMethod()
{
// Do Something
}

private void TestMethod2()
{
// Do Something
}
}

In the above, you've provided no facility in your C# for unsubscribing a
delegate. In practice, the event would normally be public and you'd
subscribe or unsubscribe directly, rather than going through a method. If
you wanted to support similar functionality in Java, obviously you'd need
an "unsubscribe" method, in which you'd use "remove()" on the
ArrayList<EventDelegate> member to remove the subscribed instance.

Of course, unlike in C# where you can easily reference the delegate method
to be removed simply by naming the method again, in Java you'd need to
save the instance you created when subscribing in the first place, so that
you can remove it later (actually, there's probably a way to use an
abstract class instead of an interface, and override equals() in the class
to match instances as long as they are effectively the same so that you
can call remove() with a new instance and still have it do the right
thing, but that seems like an awful lot of trouble to me :) ).

There are some Java conventions you might want to follow, such as naming
your interface "XXXListener", and naming the add/remove methods for the
list of listeners "addXXXListener" and "removeXXXListener".

Also note that the above is specifically designed to replicate the
multicast behavior of C# delegates, by using an ArrayList<EventDelegate>
to store your subscribers. If you don't need that(e.g. for some reason
you can guarantee that you'll only ever subscribe one delegate at a time),
you could just store a single instance of your delegate type rather than
an ArrayList of them.

Pete
 
L

Lew

Peter said:
[...]
If anybody could enlighten me here it would be great, its years since
I've
done any Java and I'm just trying to get back into it. I've included some
example C# code which probably explains better what I'm trying to do.
I see that Lew has posted a link to a good example of the human capacity
for rationalization. Buried in that article is actually an example of
how a behavior similar to delegates in C# can be implemented in Java.
Unfortunately Lew didn't bother to point out where the useful
information was amongst all that chaff.

Maybe because I found the entire article useful.

I see you have posted a good example of the human capacity for dismissing
someone's point (in this case, Sun's) without having to provide a rationale.
Simply labeling the article "a good example of the human capacity for
rationalization" doesn't invalidate anything the article has to say.

I suggest that people read the article at
<http://java.sun.com/docs/white/delegates.html>
for themselves, and then read up on C# delegates and think about the issues
for themselves.

I'm not saying I agree with Sun's reasoning, but it's clear from it that they
exercised the human capacity for rational thinking before deciding whether to
include delegates in the Java language.
 
P

Peter Duniho

Maybe because I found the entire article useful.

But was it the most useful way to answer the OP's question? I don't
believe so.
I see you have posted a good example of the human capacity for
dismissing someone's point (in this case, Sun's) without having to
provide a rationale. Simply labeling the article "a good example of the
human capacity for rationalization" doesn't invalidate anything the
article has to say.

My intent wasn't to invalidate the article. It was to answer the OP's
question. You are focusing on a single sentence out of my entire post.
Even within the same paragraph in which you found that sentence, you'll
find that my primary point is not at all about whether I agree with the
article, but rather as to whether the article was an effective way to
answer the OP's question.

The article is interesting, at least inasmuch as it provides insight
behind why there's no delegate/function pointer type in Java. But posting
a link to that article is a remarkably indirect way to answer the actual
question asked.
I suggest that people read the article at
<http://java.sun.com/docs/white/delegates.html>
for themselves, and then read up on C# delegates and think about the
issues for themselves.

Not bad advice at all. But it's not an effective way to answer the
original question. You'll note that the OP never asked why Java doesn't
have a delegate type. He asked how to accomplish the same thing he would
have in C# using a delegate type.
I'm not saying I agree with Sun's reasoning, but it's clear from it that
they exercised the human capacity for rational thinking before deciding
whether to include delegates in the Java language.

Rationalization requires rational thinking. That doesn't mean it's
necessarily the way to arrive at the correct conclusion.

More important in this context though, I think the point of a reply to the
original question should be to answer that question, in as direct and
useful a way as possible. Regardless of what you think of Sun's rationale
for excluding a delegate type, an article describing that rationale is not
even close to being the most useful way to answer the original question.

Pete
 
M

Mike Schilling

Gav said:
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.

In C# I would create a Model class which has the actual application
functions in it, a view class which is a dumb GUI and then have a
presenter class which binds the two together. The presenters
constructor takes references to the model and view then calls
methods
in the model and view classes to point a delegate to the method in
the presenter. So basically the presenter knows about the model and
view but the model and view simply fire events which call methods in
the presenter.

In general, one uses inner classes (often anonymous inner classes) in
Java to implement callbacks that would be implemented via delegates in
C#. I won't even try to explain here how that's done, but you might
look up those terms in your favorite Java reference.
 
M

Mark Space

Gav said:
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!
 
L

Lew

Peter said:
Not bad advice at all. But it's not an effective way to answer the
original question. You'll note that the OP never asked why Java doesn't
have a delegate type. He asked how to accomplish the same thing he
would have in C# using a delegate type.
More important in this context though, I think the point of a reply to
the original question should be to answer that question, in as direct
and useful a way as possible. Regardless of what you think of Sun's
rationale for excluding a delegate type, an article describing that
rationale is not even close to being the most useful way to answer the
original question.

For certain values of "effective" and "useful" I agree with you. However, I
find that providing just a bald, limited answer to a topic as fraught with
subtlety as delegates vs. inner-class pseudo-closures might not be as useful
or effective in the long run as having a full, deep understanding of what Java
does and why, which the cited article provided.

Besides, this isn't a help desk, it's a discussion group. I was discussing.

Let's make a deal. You are very knowledgeable, both about Java and C#. You
provide the simple, direct answers limited only to the precise context of the
posters' questions and I'll provide in-depth, background information to help
make those short answers more sensible overall.
 
P

Peter Duniho

I think I see what you are trying to do here, even though I'm not
familiar with C#.

For what it's worth, I think you don't see what he's trying to do there.

Your code puts the interface implementor into the Model and View classes,
used by the Presenter class. But in the OP's code, the implementor of the
interface is the Presenter class, with two different implementations, each
used by the Model and View classes, respectively.

In other words, your example is backwards as compared to what the OP was
asking.

I don't think there's anything wrong with what you wrote in your reply per
se. Except that I don't think it answers the question that was asked. :)

I suppose ultimately the OP can clarify or elaborate. But I am reasonably
familiar with C# and so I believe that my observations about the original
post and your reply are correct.

Pete
 
P

Peter Duniho

For certain values of "effective" and "useful" I agree with you.
However, I find that providing just a bald, limited answer to a topic as
fraught with subtlety as delegates vs. inner-class pseudo-closures might
not be as useful or effective in the long run as having a full, deep
understanding of what Java does and why, which the cited article
provided.

I didn't see anything in that article that discussed those subtleties in
any great detail. Instead, it seems to be more concerned with brevity of
code and run-time performance. Where it does discuss some of the more
subtle parts, it seems to be focused primarily on J#...many of the
comments don't apply in C#, or assume that one might only have a naked
method used as a delegate.

I am especially amused at the article's claim that inner classes offer
_superior_ functionality, given that in C# you can in fact implement that
exact functionality using a nested class. In other words, C# offers what
Java has, but allows you to "flatten" (the article's word) the delegate
design if you want (which in many cases makes more sense, as in those
cases the delegate method really is part of the main class...putting it in
a nested class is an arbitrary complication there).

Frankly, I find the Java design works just fine. And I think that there's
some validity to _some_ of what they write in that article. But even in
those cases, they seem to have made what I feel is an arbitrary trade-off,
sacrificing one benefit for another (for example, personally I like not
having to create a whole new class, even if anonymous, just to implement a
single-method interface, whether once or multiple times). They've
rationalized, rather than made a true determination of superior design.

In other cases, at least as compared to C#, the points aren't even
relevant (I will assume that in the context of J#, they are, but I don't
know enough about that variant to have first-hand knowledge). They make
claims that, even if they are detriments in the context of J#, don't apply
to C#. As such, they aren't relevant at all to someone who's specifically
coming from a C# context.
Besides, this isn't a help desk, it's a discussion group. I was
discussing.

If you say so. I don't personally see a single link to an article as
"discussion". Also, discussion usually comes _after_ a question has been
answered, not before (and certainly not without). But I accept that not
everyone will share that point of view.
Let's make a deal. You are very knowledgeable, both about Java and C#.
You provide the simple, direct answers limited only to the precise
context of the posters' questions and I'll provide in-depth, background
information to help make those short answers more sensible overall.

I don't like that deal. Especially since I think you're mistaken to
characterize me as being knowledgeable about Java. I've only been using
it a couple of months, for crying out loud. Just how knowledgeable could
I be?

I think a better deal would be, I'll refrain from offering any more
critique of your reply in this thread, and we can let the OP tell us which
reply he felt was the more effective and useful. If the OP tells us that
knowing _why_ the Java designers felt they should not include a delegate
type made _my_ answer more sensible overall, I'll accept your assertion
that your reply was relevant and helpful.

And let's leave future performance out of the deal altogether. Why should
either of us feel restricted in how we can answer a person's question,
assuming we are actually addressing the question?

Pete
 
P

Peter Duniho

By the way, I just ran across something in the Java docs that I think
would be useful here. In my reply, I posted a specific interface
declaration. However, I just noticed that there's a generic interface
that is probably preferable to use here. In particular:

public interface EventDelegate
{
public void Execute();
}

In C#, as with the Func<T>, Action<T>, and Action delegate types, Java has
interfaces, one generic and one not (because it doesn't need to be), that
are useful here.

The generic interface is Callable<V>, defined as having a single method
that returns the type V. So instead of declaring an explicit
delegate-like interface, one could use the Callable<V> interface for
methods that return a value.

In looking at that interface, I realized that the interface I already know
about for other reasons would serve exactly the same purpose that my
EventDelegate type serves. That is, the Runnable interface, an interface
with a single method that takes no parameters and returns void. If it
seems okay to call a method named "run()" in the code at the appropriate
point, then Runnable would work just as well as the interface I suggested
earlier.

I realize this is a relatively minor point, but I think it's a good idea
to use the framework-provided types where appropriate. And they
definitely seem appropriate here.

Pete
 
M

Mark Space

Peter said:
Your code puts the interface implementor into the Model and View
classes, used by the Presenter class. But in the OP's code, the
implementor of the interface is the Presenter class, with two different
implementations, each used by the Model and View classes, respectively.

I think the OP was trying to show test methods (ie. unit test harness).
I showed a production example. It would be trivial to substitute an
instance method in Presenter for doIt() in the interface.

The other bit in the OP's code I think is a call-back that would be
implemented in the view (which I did not show). Again, the OP is
showing a unit test. Same deal, just use a different method call.

I could be wrong of course, but I think you're all wet.
 
M

Mark Space

Peter said:
The generic interface is Callable<V>, defined as having a single method
In looking at that interface, I realized that the interface I already
know about for other reasons would serve exactly the same purpose that
my EventDelegate type serves. That is, the Runnable interface, an

Sorry but this is poor advice. Don't use Callable or Runnable. Use
java.awt.event.ActionListener. You'll end up tying yourself in knots
otherwise.

Callable and Runnable aren't general purpose delegates. They are highly
specific and should only be used when they are needed. For GUI work,
you won't need them very often. Use the classes in javax.swing and
java.awt.
 
P

Peter Duniho

[...]
I could be wrong of course, but I think you're all wet.

Well, tell you what: when you've actually learned C#, write a program that
executes the code the OP posted. Then run the code you posted. And then
come back and tell us if the two pieces of code do the same thing.

I think you're all wet too, but I've got better manners than to say so
publicly. I prefer instead to focus on the technical, objective issues,
rather than throwing personal insults around. Maybe I should have stated
more emphatically that your reply was incorrect. It certainly was my own
mistake for assuming that once your mistake was pointed out, you'd
acknowledge it gracefully.

Pete
 
P

Peter Duniho

Sorry but this is poor advice. Don't use Callable or Runnable. Use
java.awt.event.ActionListener. You'll end up tying yourself in knots
otherwise.

Hmmm? ActionListener seems at least as context-specific as Runnable.
Callable and Runnable aren't general purpose delegates.

Well, neither is ActionListener.

If you've got an example of a truly general-purpose interface that Java
offers, I'll agree that my previous advice was flawed. But I don't see
how replacing one special-purpose interface with another improves the
situation.

I do understand what you mean about Callable and Runnable being specific
to a given scenario, and I'd agree that an interface that is more
specifically intended as a general-purpose interface would be better (much
better, in fact). But the pattern of those interfaces is itself more
general-purpose than that of ActionListener. I don't see how the latter
is superior to the former.

Pete
 
M

Mark Space

Peter said:
[...]
I could be wrong of course, but I think you're all wet.

Well, tell you what: when you've actually learned C#, write a program
that executes the code the OP posted. Then run the code you posted.
And then come back and tell us if the two pieces of code do the same thing.

Since the OP is actually asking about Java in a Java group, why don't
you post some working Java code, like I did. Seriously. If my examples
are that bad (and every one of those three programs executed correctly),
I'd appreciate seeing a corrected example.
 
P

Peter Duniho

Since the OP is actually asking about Java in a Java group, why don't
you post some working Java code, like I did.

I did.
Seriously.
Seriously.

If my examples are that bad (and every one of those three programs
executed correctly),

Define "correctly". None of your examples behaves in the way that the
OP's code does. I wouldn't call that correct.

And I never said your examples were bad. In fact, I specifically wrote "I
don't think there's anything wrong with what you wrote in your reply per
se". They demonstrate a useful behavior. They just don't demonstrate the
same behavior that the OP is looking for.
I'd appreciate seeing a corrected example.

Just look at my first reply to the OP.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top