R
raylopez99
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();
////////////////////////////////////
}
}
}
///////////////////
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();
////////////////////////////////////
}
}
}
///////////////////