473,412 Members | 3,763 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,412 software developers and data experts.

Mediator class design pattern (two different ways)

Here are two different ways of achieving a mediator pattern: the
first, using circular references (for lack of a better way to describe
it), but not using delegates, with the second using delegates.

The first way is an adaptation from C++ for Dummies by Jeff Cogswell.
But obviously it uses references not pointers.

The second way (I'll post this later, as I haven't yet done it) will
be adapted from the book C#3.0 Design Patterns by Judith Bishop, and
it uses delegates.

Which way do I prefer? Both, but they're both "mind bending" to a
degree. Perhaps, once you get used to delegates, the Judith Bishop
delegate way is easier to write, but the 'classic' way by Cogswell is
also good, and it's the way I initially learned about the mediator
design pattern when coding in C++.

A quick note to what exactly a mediator class pattern is: it's like a
hub and spoke system--the mediator (the hub) communicates with a bunch
of classes (at the spokes) and is the 'switchboard' through which
these spokes communicate to one another and are controlled by the
hub. That is, for a class on one 'spoke' to communicate with another
class on another 'spoke', it has to go through the 'hub' mediator.
Why do this? Because otherwise you'll have that classic "N-star" of
connections problem, so that everytime you add a class you have to
connect it to talk to all the other preexisting classes, which quickly
becomes unmanageable.

Here is the code for the non-delegate version:

// October 6, 2008

//output - works fine, as expected.

/*
The gist is this: the mediator class has as member variables all the
classes on the 'spokes', here called 'OtherClass2' and '3', which
inherit from a base class called 'OtherClass', and using the method
"PartChanged" as well as the 'trick' as indicated below (keyword:
'trick'), it can change and/or communicate with any spoke class.
*/

//output:
o is OtherClass 2 type: MediatorC.OtherClass2 having value:2
o is OtherClass 3 type: MediatorC.OtherClass3 having value:1
o is OtherClass 3 type: MediatorC.OtherClass3 having value:1001
OtherClass3 one thous: 1001
notice now myoc3.oci3 is 1001!: 1001
now decrement myoc2 by ten
o is OtherClass 2 type: MediatorC.OtherClass2 having value:-8
now square both values myoc2 and myoc3
squared values myoc2,3 are: 64, 1002001 //1001^2 = 1002001

the end

Press any key to continue . . .

// Mediator Class Adapted from C++ for Dummies by Jeff Cogswell

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MediatorC
{
class Mediator
{
public int m;
// public OtherClass oc;
public OtherClass2 myoc2;
public OtherClass3 myoc3;
public Mediator()
{
m = 1;
myoc2 = new OtherClass2(this);
myoc3 = new OtherClass3(this);

}

public void PartChanged(OtherClass o)
{

if (o is OtherClass2)
{
OtherClass2 oceye2 = (OtherClass2)o;
Console.WriteLine("o is OtherClass 2 type: {0} having
value:{1}", oceye2.GetType(), oceye2.oci2);

if (oceye2.oci2 10)
{
Console.WriteLine("OtherClass2 ten: {0}",
oceye2.oci2);

}
}
if (o is OtherClass3)
{
OtherClass3 oceye3;
oceye3 = (OtherClass3)o;
Console.WriteLine("o is OtherClass 3 type: {0} having
value:{1}", oceye3.GetType(), oceye3.oci3);

if (oceye3.oci3 1000)
{
Console.WriteLine("OtherClass3 one thous: {0}",
oceye3.oci3);

}
}

}

public void DoSomething()
{
myoc2.UniqueFunc_Cl2(1);
myoc3.UniqueFunc_C13(0);
myoc3.UniqueFunc_Cl3(1000); //notice how you can access
myoc3 public functions and, via the 'trick' below, the 'spoke' class
myoc3 can talk back to the mediator class
if (myoc3.oci3 >= 1000)
{
Console.WriteLine("notice now myoc3.oci3 is 1001!:
{0}", myoc3.oci3);
Console.WriteLine("now decrement myoc2 by ten");
myoc2.UniqueFunc_Cl2(-10);
}
Console.WriteLine("now square both values myoc2 and
myoc3");
OtherClass tempOtherClassbaseRef;
tempOtherClassbaseRef = myoc2;
int iSq =
tempOtherClassbaseRef.ReturnTheInt_oci_Squared();
tempOtherClassbaseRef = myoc3;
int jSq =
tempOtherClassbaseRef.ReturnTheInt_oci_Squared();
Console.WriteLine("squared values myoc2,3 are: {0}, {1}",
iSq, jSq);
Console.WriteLine("\n the end \n");
}

}

class OtherClass
{
private int _oci;
Mediator AMediator;

public int oci
{
get { return _oci; }
set { _oci = value; }
}

public OtherClass(Mediator m)
{
_oci = m.m;
AMediator = m; //trick! This exists in the base class of
the 'spoke' classes and is required
}

public void Changed()
{
AMediator.PartChanged(this); //trick! This exists in the
base class of the 'spoke' classes and is required }

public virtual int ReturnTheInt_oci_Squared()
{
return -1;
}

public virtual void incr_oci()
{ _oci++; }

}

class OtherClass2:OtherClass
{
private int _oci2;
public int oci2
{
get { return _oci2; }
set { _oci2 = value; }
}
public OtherClass2(Mediator M):base(M)
{
_oci2 = M.m;
}
public override int ReturnTheInt_oci_Squared()
{
return oci2*oci2;
}
public override void incr_oci()
{ _oci2++; }

public void UniqueFunc_Cl2(int idelta)
{
_oci2 = _oci2 + idelta;
base.Changed(); //this tells base, and ultimately
Mediator, that something has changed in derived class
//trick!

}

}

class OtherClass3 : OtherClass
{
private int _oci3;
public int oci3
{
get { return _oci3; }
set { _oci3 = value; }
}

public OtherClass3(Mediator m): base(m)
{
_oci3 = m.m;
}

public override int ReturnTheInt_oci_Squared()
{
return oci3*oci3;
}

public override void incr_oci()
{ _oci3++; }

public void UniqueFunc_Cl3(int idelta)
{
_oci3 = _oci3 + idelta;
base.Changed(); //this tells base, and ultimately
Mediator, that something has changed in derived class
//trick!
}

}

//of course, you can add as many "spoke" classes, OtherClass4,
OtherClass5, etc., as you want here, and the functions above
"UniqueFunc" etc are completely arbitrary. The important code is the
'trick' and similar infrastructure code

}
//////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MediatorC
{
class Program
{
static void Main(string[] args)
{
Mediator myMed = new Mediator();
myMed.DoSomething();

////////////////////////////////////
}
}
}
///////////////////

Oct 6 '08 #1
9 2381
"raylopez99" <ra********@yahoo.comwrote in message
news:f1**********************************@t65g2000 hsf.googlegroups.com...
>
Which way do I prefer? Both, but they're both "mind bending" to a
degree.
I'd call them pretty obvious. Why are you posting your long essays on stuff
beginners learn with ease?

- Michael Starberg
Oct 6 '08 #2
On Oct 6, 5:23*am, "Michael S" <n...@no.nowrote:
I'd call them pretty obvious. Why are you posting your long essays on stuff
beginners learn with ease?

- Michael Starberg

It's not obvious. In fact, I think there's a typo in Bishops mediator
pattern--trying to figure it out now. If it's obvious, please post a
mediator that uses delegates.

RL

Oct 6 '08 #3
How about:

public partial class Form1 : Form
{
Controller controller = new Controller();
public Form1()
{
...
controller.NotifyDispatcher += new
Mortgage.NotifyHandler(Form1_OnINotifyEvent);
controller.NotifyDispatcher += total.GetNotifyHandler();
}
...}
public class Controller : Mortgage.IUpdate
{
Model model = new Model();

public event Mortgage.NotifyHandler NotifyDispatcher;
public bool Update(Mortgage.Parameters mp)
{
Mortgage.Calculation mc = model.Calculate(mp);
if (mc.IsValid())
{
// fire event to all registered listeners of change in
model state
NotifyDispatcher(this, new
Mortgage.MortgageEventArgs(mc));
return true;
}
else return false; // do nothing if input data is invalid
}
Regards,
Jeff

*** Sent via Developersdex http://www.developersdex.com ***
Oct 6 '08 #4
On Oct 6, 2:00*pm, Jeff Louie <anonym...@devdex.comwrote:
How about:
Regards,
Jeff
Thanks, but I don't see it. This looks more like a standard "events"
model, where one object can notify other objects that an event has
occurred (" // fire event to all registered listeners of change in
model state ")

In a mediator class, you need a mediator and at least two other
classes, with the mediator being able to pass messages from one class
to the other. In fact, what I'm debating now in my example that I'm
writing (should be done in a day or two, as I just code for fun) is
whether the two classes should "live" inside the mediator (as in my
original example) or, as is the case in Judith Bishop's example (where
the two classes don't talk to one another, as I propose), they should
be independently instantiated outside the mediator itself.

RL

Oct 7 '08 #5
On Oct 5, 5:05*pm, raylopez99 <raylope...@yahoo.comwrote:
Here are two different ways of achieving a mediator pattern: *the
first, using circular references (for lack of a better way to describe
it), but not using delegates, with the second using delegates.

The first way is an adaptation from C++ for Dummies by Jeff Cogswell.
But obviously it uses references not pointers.

The second way (I'll post this later, as I haven't yet done it) will
be adapted from the book C#3.0 Design Patterns by Judith Bishop, and
it uses delegates.
Here is a mediator class using the 'second way' I mentioned above,
modeled after a design pattern in Judith Bishop's book.

BTW, you can see a delegate is essentially a global "GOTO". Why do I
say this? Because check out what happens at the point ^&* below. And
the statement:" //^&* note once .Send1 fired, then rest of statement
is not executed, even AFTER the throw is done and you would think the
call would be ‘unwound’ to end up back here (i.e., as if it were
recursive)". If delegates were not a global GOTO then logically after
the call ended, the program would continue, like a recursive call,
where it left off. But it does not. In short, delegates (and events,
which are a form of delegate) are a kind of global GOTO.

This program does the following: two classes, which inherit from a
base class, receive information from a mediator class that is common
to both (as a composite member variable/class). By using if/then/else
statements the two classes are able to 'talk' to one another through
the mediator, which broadcasts messages (information, here a string,
int, and char) to all subscribers (a rather inelegant way, but short
of introducing another delegate, which would have been confusing, I
could not think of any better way...please let me know if there is
one).

One class Colleague 1, handles even numbers using the if statement "if
(i%2 == 0) ..."and the other, Colleague2 handles odd numbers, but both
always receive messages (information) broadcast by the Mediator
class. Upon a randomly generated 'magic number' being hit --I made
the magic number(s) 3,5,7,9--the one class broadcasts itself (using
mediator.Send1, see the comment "//this is key") to all other classes,
which then, using if/then logic, can do stuff with these magic
numbers.

Pretty slick eh?

Next time, I will include a bunch of delegates that will be in a hash
table and/or dictionary and you can look them up by a key.

RL

//////// OUTPUT (when a magic number, here 5, happened to be triggered
by the random number generator)

inside SendC1: j
Colleague1 name here: john, String: john, int:10, char: j random_i:5
Colleague2 name: lucy, string: maGiC X!, odd int: 5, char:x
Colleague1 name(2): john5, String: john, int:10, random int: 5 char:x
Press any key to continue . . .
////////////////////
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MediatorC
{

class Mediator
{
public delegate int Callback1(string msg, int i, char c);
Callback1 respond1;
public void SignOn(Callback1 method1)
{
respond1 += new Callback1(method1);

}

public int Send1(string msg, int i, char c)
{
int j=-1;
if (respond1 != null)
{
if (c == 'x')
{// begin magic 'x' broadcast
j = respond1.Invoke(msg, i, c);
}
else
{

j = respond1.Invoke(msg, i, c);
}
}
return j;
}

public Mediator()
{
}

}

class Colleague
{
protected int iC1;
protected string strC1;
protected char cC1;
protected Mediator mediator;
public Colleague(Mediator m, string s, int i, char c)
{
this.mediator = m;
mediator.SignOn(Receive);
strC1 = s; cC1 = c;
}

public virtual int Receive(string s, int i, char c)
{
// virtual function
return 0;
}

public int SendC1(int iSC)
{

int i_temp;
Console.WriteLine("inside SendC1: {0}", cC1.ToString());
i_temp = mediator.Send1(strC1, iSC, cC1);
return i_temp;
}

}

class Colleague1:Colleague //even Colleague1 is even numbers
{

public Colleague1(Mediator m, string s, int i, char c)
: base(m, s, i, c)
{ }

public override int Receive(string s, int i, char c)
{
int temp_return_i = -1;
if (i % 2 == 0)
{
int j = RandomINT.RandomInt();

Console.WriteLine("Colleague1 name here: {0}, String: {1},
int:{2}, char: {3} random_i:{4}",strC1, s, i.ToString(), c.ToString(),
j);

temp_return_i = i;
iC1 = j;
strC1 = strC1 + j.ToString();
if (j == 3 || j == 5 || j ==7 || j ==9)
{
cC1 = 'x'; //magic 'x' routine
mediator.Send1("maGiC X!", j, 'x'); //magic 'x'
broadcast (this is key)
//^&* note once .Send1 fired, then rest of statement below, namely,
Console.WriteLine("Colleague1 name(2)...", is not executed, even AFTER
the throw is done and you would think the call would be ‘unwound’ to
end up back here (i.e., as if it were recursive)
}
Console.WriteLine("Colleague1 name(2): {0}, String: {1},
int:{2}, random int: {3} char:{4}", strC1, s, i.ToString(), j,
cC1.ToString());

}

return temp_return_i;
}

}

class Colleague2:Colleague //odd numbers
{
public Colleague2(Mediator m, string s, int i, char c)
: base(m, s, i, c)
{ }

public override int Receive(string s, int i, char c)
{
int temp_return_i = -1;

if (c == 'x')
{
//magic x! routine
Console.WriteLine("Colleague2 name: {0}, string: {1},
odd int: {2}, char:{3}", strC1, s, i, c);
}
else
{
if ((i % 2) != 0)
{
Console.WriteLine("Colleague2 name here: {0},
String: {1}, int:{2}, char: {3}", strC1, s, i, c.ToString());
temp_return_i = i;
//return temp_return_i;
}
}

return temp_return_i;
}

}

public static class RandomINT
{
public static int RandomInt()
{
Random myRandomInt = new Random();
return myRandomInt.Next(1, 10);
//static class random number generator
}
}

}
//////////////
// main here
namespace MediatorC
{
class Program
{
static void Main(string[] args)
{

Mediator m = new Mediator();
Colleague2 head2 = new Colleague2(m, "lucy", 11, 'l');
Colleague1 head1 = new Colleague1(m, "john", 10, 'j');

head1.SendC1(10); //colleague1 is even numbers

}
}
}
//////////////////

Oct 9 '08 #6
On Oct 8, 5:38*pm, raylopez99 <raylope...@yahoo.comwrote:
BTW, you can see a delegate is essentially a global "GOTO". *Why do I
say this? *Because check out what happens at the point ^&* below. And
the statement:" //^&* note once .Send1 fired, then rest of statement
is not executed, even AFTER the throw is done and you would think the
call would be ‘unwound’ to end up back here (i.e., as if it were
recursive)". *If delegates were not a global GOTO then logically after
the call ended, the program would continue, like a recursive call,
where it left off. *But it does not. *In short, delegates (and events,
which are a form of delegate) are a kind of global GOTO.
OK I take that back. Upon closer inspection it looks like in fact the
program is 'unwound' like in a recursive manner, or picking up where
it left off. So delegates are not entirely like a GOTO.

BTW, here is the output without a magic number:

/*
inside SendC1: j
Colleague1 name here: john, String: john, int:10, char: j random_i:6
Colleague1 name(2): john6, String: john, int:10, random int: 6 char:j
Press any key to continue . . .
*/

And if you put this line(s) in main:
head1.SendC1(10); //colleague1 is even numbers
head2.SendC1(11); //colleague2 is odd numbers

you get this output, when there is no 'magic number' generated:

/*
inside SendC1: j
Colleague1 name here: john, String: john, int:10, char: j random_i:4
Colleague1 name(2): john4, String: john, int:10, random int: 4 char:j
inside SendC1: l
Colleague2 name here: lucy, String: lucy, int:11, char: l
Press any key to continue . . .
*/

RL
Oct 9 '08 #7
raylopez99 <ra********@yahoo.comwrote:
BTW, you can see a delegate is essentially a global "GOTO". *Why do I
say this? *Because check out what happens at the point ^&* below. And
the statement:" //^&* note once .Send1 fired, then rest of statement
is not executed, even AFTER the throw is done and you would think the
call would be =3Funwound=3F to end up back here (i.e., as if it were
recursive)". *If delegates were not a global GOTO then logically after
the call ended, the program would continue, like a recursive call,
where it left off. *But it does not. *In short, delegates (and events,
which are a form of delegate) are a kind of global GOTO.
OK I take that back. Upon closer inspection it looks like in fact the
program is 'unwound' like in a recursive manner, or picking up where
it left off. So delegates are not entirely like a GOTO.
Indeed, they're nothing like GOTO - as you've been informed several
times in the past.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Oct 9 '08 #8
On Oct 8, 7:15*pm, Jon Skeet [C# MVP] <sk...@pobox.comwrote:
>
Indeed, they're nothing like GOTO - as you've been informed several
times in the past.
Hey Jon--up to p. 85 (Chapter 3, Advanced Generics) in your book. Gets
bogged down a bit here...but good stuff. I went through your example
on p. 84 and will post a modification of it in another thread.

Ray
Oct 9 '08 #9
raylopez99 <ra********@yahoo.comwrote:
Indeed, they're nothing like GOTO - as you've been informed several
times in the past.

Hey Jon--up to p. 85 (Chapter 3, Advanced Generics) in your book. Gets
bogged down a bit here...but good stuff. I went through your example
on p. 84 and will post a modification of it in another thread.
Hopefully when you get to later on in the book you'll have more
appreciation for lambda expressions :)

I tried my hardest to stop the generics chapter from getting *too*
heavy, but some topics just can't be explained easily :( There's
another section (third part of chapter 9, from memory) which talks
about the changes to type inference for generics - that's possibly the
"boggiest" bit of the book, but it's more for later reference than
anything else.

--
Jon Skeet - <sk***@pobox.com>
Web site: http://www.pobox.com/~skeet
Blog: http://www.msmvps.com/jon.skeet
C# in Depth: http://csharpindepth.com
Oct 9 '08 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: cppaddict | last post by:
I have a design question which I am posting here because the implementation will be in C++ and I think there may be C++ specific language constructs (eg, friends) that might be relevant to the...
1
by: Coder-X | last post by:
Hi, can someone give a real app example of where the Mediator design pattern could be used ( for instance in a relational database application )? Thanks, José Carlos Ferreira
15
by: Joe Fallon | last post by:
I would like to know how you can figure out how much memory a given instance of a class is using. For example, if I load a collection class with 10 items it might use 1KB, and if I load it with...
1
by: FluffyCat | last post by:
I finally pieced together what I think is a good example of the Mediator Pattern in PHP 5. See what you think. http://www.fluffycat.com/PHP-Design-Patterns/Mediator/ I have, per request,...
22
by: Krivenok Dmitry | last post by:
Hello All! I am trying to implement my own Design Patterns Library. I have read the following documentation about Observer Pattern: 1) Design Patterns by GoF Classic description of Observer....
26
by: nyathancha | last post by:
Hi, How Do I create an instance of a derived class from an instance of a base class, essentially wrapping up an existing base class with some additional functionality. The reason I need this is...
1
by: halekio | last post by:
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...
1
by: halekio | last post by:
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...
6
by: Bhawna | last post by:
I am into c++ code maintenance for last 3-4 years but recently I am put into design phase of a new project. Being a small comapany I dont have enough guidance from seniors. Currently I am into a...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.