c#: inter-object event messaging (mediator pattern?)

H

halekio

Hi all,

Please bear with me as I've only started programming in C# 2 weeks ago
and this is my first contact with OOP.

I ran into a situation where I needed to catch an event in an object
that had no connection or reference to the object that triggered it.

It goes something like this: (not syntactically correct..it's just for
the idea)

main()
{ A a;
C c;
a.Run();
}

class A
{ B b;
C c;

Run()
{ // Trigger the Event here}
} // class

class B
{ C c;
}

class C
{ // Catch and handle the event here
}

Which means that the event would be handled by the 3 instances of C.

From My research I gathered that I should be using something called
the "Mediator Pattern".
Unfortunately I could not find a working example of this.

Also, from what I was able to understand, to make it work with this
pattern would require that I derive class C from an abstract
"participant". Is that right ?

I then kind of gave up on trying to make it work with this pattern
(out of frustration at my failures) and proceeded to try and implement
something that I was a bit more familiar with (from my backgroung with
PCS):
The Publish / Subscribe model (is that also known as a pattern?)


I was pleasantly surprised that it worked.
Here's my working implementation:

All classes use the following:
using System;
using System.Collections.Generic;
using System.Text;

With the class Dispatcher also using:
using System.Collections;


class Program
{
static void Main(string[] args)
{
A a = new A();
C c = new C("C1");

for(int i = 1; i <= 3; i++)
{
a.Run(i);
}
Console.ReadKey();
}
}

class A
{
B b = new B();
C c = new C("C2");

public void Run(int i)
{
Dispatcher.Publish("MyEvent", "Hello #" + i.ToString());
}
}

class B
{
C c = new C("C3");
}

class C
{
private string name;

public C(string name)
{
this.name = name;
Dispatcher.Subscribe("MyEvent", OnMyEvent);
}

public void OnMyEvent(object appEventParams)
{
string textReceived = (string)appEventParams;
Console.WriteLine(textReceived + " received in " + name);
}

}

public delegate void AppEventHandler(object appEventParams);

static class Dispatcher
{
private static Hashtable registry = new Hashtable();

public static void Subscribe(string appEvent, AppEventHandler
appEventHandler)
{
Subscription(appEvent, appEventHandler, true);
}

public static void Unsubscribe(string appEvent,
AppEventHandler appEventHandler)
{
Subscription(appEvent, appEventHandler, false);
}

private static void Subscription(string appEvent,
AppEventHandler appEventHandler, bool add)
{
ArrayList list;

if (add)
{
if (registry[appEvent] == null)
registry.Add(appEvent, new ArrayList());

list = (ArrayList)registry[appEvent];
list.Add(appEventHandler);
}
else
{
if (registry[appEvent] != null)
{
list = (ArrayList)registry[appEvent];
list.Remove(appEventHandler);
}
}
}

public static void Publish(string appEvent, object
appEventParams)
{
ArrayList list;
AppEventHandler appEventHandler;

if (registry[appEvent] != null)
{
list = (ArrayList)registry[appEvent];

for (int i = 0; i < list.Count; i++)
{
appEventHandler = (AppEventHandler)list;
if (appEventHandler != null)
appEventHandler(appEventParams);
}
}
}
}


The ouput is:
Hello #1 received in C3
Hello #1 received in C2
Hello #1 received in C1
Hello #2 received in C3
Hello #2 received in C2
Hello #2 received in C1
Hello #3 received in C3
Hello #3 received in C2
Hello #3 received in C1

Here are my questions (about time you'll say...sorry about that too
long preambule):

1) Is 'this" somehow a valid implementation of the Mediator pattern
and if not, it is known under another name ? (I hope it's not one of
those anti-pattern)

2) If it's not a valid implementation of the Mediator pattern (or
another "good" pattern), is there any reason why you would advise
"against" this approach. Did I miss an obvious flaw ? Did I do a big
no-no ?

3) Could you "please" (pretty, pretty please) give me a valid
implementation of the Mediator pattern that would give me the exact
same behavior as in my example. (If possible please give me working
code)

4) Any other comments, good of bad, that you think might help me with
this problem.

Thanks a lot in advance.
 
P

Peter Duniho

[...]
Which means that the event would be handled by the 3 instances of C.

From My research I gathered that I should be using something called
the "Mediator Pattern".
Unfortunately I could not find a working example of this.

I'd never heard the phrase "mediator pattern" until your post. :) As near
as I can tell from the Wikipedia article on the topic, the "mediator
pattern" is simply a way of describing an inter-object communications
paradigm in which an intermediate (or "mediating") object handles the
communications.

It seems to me that if you have a general-purpose event to which a variety
of different classes may want to subscribe, then the mediator pattern makes
sense. If, on the other hand, you have a special-purpose event to which
only a specific class will subscribe, I don't think you need a mediator
class and the mediator pattern doesn't make sense.
Also, from what I was able to understand, to make it work with this
pattern would require that I derive class C from an abstract
"participant". Is that right ?

I guess that depends on how rigidly the authors of the "Design Patterns"
book have defined "mediator pattern".
I then kind of gave up on trying to make it work with this pattern
(out of frustration at my failures) and proceeded to try and implement
something that I was a bit more familiar with (from my backgroung with
PCS):
The Publish / Subscribe model (is that also known as a pattern?)

It seems to me that the publish/subscribe model you implemented is in fact
an example of a mediator pattern. Again, I suppose it really depends on how
rigidly the term has actually been defined. But in the code you wrote, an
intermediate class handles communications between other classes. As such,
that intermediate class could be thought of as a mediator, and the design
could be thought of as a "mediator pattern".
[...]
1) Is 'this" somehow a valid implementation of the Mediator pattern
and if not, it is known under another name ? (I hope it's not one of
those anti-pattern)

See above. I would call it an example of "the mediator pattern".
2) If it's not a valid implementation of the Mediator pattern (or
another "good" pattern), is there any reason why you would advise
"against" this approach. Did I miss an obvious flaw ? Did I do a big
no-no ?

I don't see anything obvious wrong with your implementation. It seems to me
that it could be a little more concise, especially if you don't really have
the need for named events (that is, if you really only have a single event
to deal with), since C# includes built-in support for a data type called an
"event" that wraps up the subscribe/unsubscribe functionality for you.
Likewise, if you know it will always be an instance of class C that
subscribes to the event, you could even have an explicit event within class
C to which instances add themselves and which is signaled by a specific
method in class C.

But all those are just variations on the theme, and if you really need the
general-purpose behavior you've implemented, then I don't really see much in
the way of significant improvements (I don't like the design of combining
both the subscribe and unsubscribe behavior into a single method, but that's
your choice I guess).

One minor quibble (besides the "two behaviors in one method I mention
above):

You might consider removing your ArrayList instance from the Hashtable
if you've just removed the last entry of the ArrayList. Not a big deal if
you have very few events, or if you have a lot of events but don't expect
any of them to be empty for very long (as in, clients only unsubscribe when
the application is shutting down). But it just seems nicer to me.

Now that you ask the question, it seems to me that the C# "event" is missing
something. That is, as near as I can tell you can only ever define a
specific instance of an event. You can't have the type of an event, which
means that you can't add a dynamically created event to a collection, which
means that you can't enjoy the type-safeness of events while at the same
time providing a named-event paradigm such as the one your Dispatcher class
does.

Maybe I'm wrong about the limitations of the C# "event". I'm no expert in
using them, and I might have missed something. If so, hopefully someone
else will pipe up. I think it would be really cool if you could use a
Dictionary to maintain a list of dynamically created events, indexed by
name. It wouldn't change the code you've suggested very much, but it would
allow it to be type-safe (that is, you would only be able to add delegates
of the correct type to a specific event).

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

Top