Re: Delegates...?
On Thu, 21 Feb 2008 03:37:15 -0800, Gav =
<postmaster@gavinmetcalfe.plus.net> wrote:
[...]
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 s=
ome
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 h=
ow =
a behavior similar to delegates in C# can be implemented in Java. =
Unfortunately Lew didn't bother to point out where the useful informatio=
n =
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. The=
n =
you implement the interface (in your main class, in an inner/nested clas=
s =
that you can instantiate as needed, or using an anonymous inner class) a=
nd =
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<EventDelegate> Test = new ArrayList<EventDelega=
te>();
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<EventDelegate>();
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 nee=
d =
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 meth=
od =
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 th=
at =
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 cla=
ss =
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