When we learn the Observer Pattern, we will see the Figure like this:
It come from the << Head.First.Design.Patterns>>. Let us to learn this pattern together....
Observer is a abstract class or interface, it define a series of methods. these methods can be executed when the Subject have a notify to happen. Now, i give some code to analyse it:
namespace
ObserverPattern2
{
class
Program
{
static
void
Main(
string
[] args)
{
Observer1 o1
=
new
Observer1();
Observer2 o2
=
new
Observer2();
Subject subject
=
new
Subject();
subject.RegisterObserver(o1);
subject.RegisterObserver(o2);
subject.Notify(
"
billok
"
);
subject.Notify(
"
billchen
"
);
subject.RemoveObserver(o2);
subject.Notify(
"
cjb
"
);
Console.ReadLine();
}
}
public
abstract
class
Observer
{
public
abstract
void
Update(
string
userName);
}
public
class
Observer1 : Observer
{
public
override
void
Update(
string
userName)
{
Console.WriteLine(
"
Update Observer1
"
+
userName);
}
}
public
class
Observer2 : Observer
{
public
override
void
Update(
string
userName)
{
Console.WriteLine(
"
Update Observer2
"
+
userName);
}
}
public
interface
ISubject
{
void
RegisterObserver(Observer observer);
//
register an Observer
void
RemoveObserver(Observer observer);
//
remove an Observer
void
Notify(
string
userName);
//
notify observers when the state is changed
}
public
class
Subject : ISubject
{
private
List
<
Observer
>
observers;
public
Subject()
{
observers
=
new
List
<
Observer
>
();
}
public
void
RegisterObserver(Observer observer)
{
if
(
!
observers.Contains(observer))
observers.Add(observer);
}
public
void
RemoveObserver(Observer observer)
{
int
i
=
observers.IndexOf(observer);
if
(i
>=
0
)
observers.Remove(observer);
}
public
void
Notify(
string
userName)
{
foreach
(Observer observer
in
observers)
{
observer.Update(userName);
}
}
}
}
Observer1 and Observer2 are the implement of abstract Observer. They really finish the Update(string userName) method. This method will be executed when Observer is notified.
How to notify these Observer? It is Subject's duty. ISubject define three methods(RegisterObserver, RemoveObserver, Notify). RegisterObserver is used to register a new Observer, this observer will be notified when subject's Notify method is executed.
RemoveObserver is used to remove existent Observer, then it will be not notified.
Notify is used to tigger an action, this action will be notify all of Observers of the storage of the Subject.
Now, Subject is a implementing class of the ISubject interface.
How to use this Observer Pattern to finish our job? First, we can create a Subject object, and create some Observer's implements. Next, you add the objects to the Subject object by RegisterObserver method. Finally, we execute the Notify method, and all of the Observer will be notified and their Update method will be executed.
Maybe you can take note of my codes is differ from the Figure. In the Figure, ConcreteObserver class have a reference of the ISubject. we can come true it. I think it's duty is simply register itseft to the subject. Let us to add a Isubject reference to the Observer, like this:
public
abstract
class
Observer
{
private
ISubject iSubject;
private
Observer() { }
public
Observer(ISubject iSubject)
{
this
.iSubject
=
iSubject;
this
.iSubject.RegisterObserver(
this
);
//
register itseft
}
public
abstract
void
Update(
string
userName);
}
when we new a Observer object, reference of ISubject is added to the new object. Now, we may modify the using of the RegisterObserve. Please look this:
Subject subject
=
new
Subject();
Observer1 o1
=
new
Observer1(subject);
Observer2 o2
=
new
Observer2(subject);
subject.Notify(
"
billok
"
);
Okay, i give another version:
another version
namespace ObserverPattern2_2
{
class Program
{
static void Main(string[] args)
{
Subject subject = new Subject();
Observer1 o1 = new Observer1(subject);
Observer2 o2 = new Observer2(subject);
subject.Notify("billok");
subject.Notify("billchen");
subject.RemoveObserver(o2);
subject.Notify("cjb");
Console.ReadLine();
}
}
public abstract class Observer
{
private ISubject iSubject;
private Observer() { }
public Observer(ISubject iSubject)
{
this.iSubject = iSubject;
this.iSubject.RegisterObserver(this);//register itseft
}
public abstract void Update(string userName);
}
public class Observer1 : Observer
{
public Observer1(ISubject iSubject) : base(iSubject) { }
public override void Update(string userName)
{
Console.WriteLine("Update Observer1 " + userName);
}
}
public class Observer2 : Observer
{
public Observer2(ISubject iSubject) : base(iSubject) { }
public override void Update(string userName)
{
Console.WriteLine("Update Observer2 " + userName);
}
}
public interface ISubject
{
void RegisterObserver(Observer observer);//register an Observer
void RemoveObserver(Observer observer);//remove an Observer
void Notify(string userName);//notify observers when the state is changed
}
public class Subject : ISubject
{
private List<Observer> observers;
public Subject()
{
observers = new List<Observer>();
}
public void RegisterObserver(Observer observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
}
public void RemoveObserver(Observer observer)
{
int i = observers.IndexOf(observer);
if (i >= 0)
observers.Remove(observer);
}
public void Notify(string userName)
{
foreach (Observer observer in observers)
{
observer.Update(userName);
}
}
}
}
Okay, Now! Let us take attention to the implement of Observer Pattern in C#.
We should use the Delegate and Event to implement the Observer Pattern in the .NET Framework. I give the new edition for .net like it:
namespace
ObserverPattern3
{
class
Program
{
static
void
Main(
string
[] args)
{
Trigger trigger
=
new
Trigger();
trigger.Changed
+=
new
Trigger.ChangedEventHandler(trigger_Changed);
trigger.Changed
+=
delegate
(
object
sender, ChangedEventArgs e)
{
Console.WriteLine(
"
delegate Observer:
"
+
e.UserName);
};
trigger.Changed
+=
Observer1;
trigger.Changed
+=
Observer2;
trigger.Update(
"
billok
"
);
trigger.Changed
-=
Observer2;
trigger.Update(
"
cjb
"
);
Console.ReadLine();
}
static
void
trigger_Changed(
object
sender, ChangedEventArgs e)
{
Console.WriteLine(
"
custom Observer:
"
+
e.UserName);
}
public
static
void
Observer1(Object sender, ChangedEventArgs e)
{
Console.WriteLine(
"
Observer1:
"
+
e.UserName);
}
public
static
void
Observer2(Object sender, ChangedEventArgs e)
{
Console.WriteLine(
"
Observer2:
"
+
e.UserName);
}
}
public
class
ChangedEventArgs : EventArgs
{
public
readonly
string
UserName;
public
ChangedEventArgs(
string
userName)
{
this
.UserName
=
userName;
}
}
public
class
Trigger
{
//
declare a delegate variable.
public
delegate
void
ChangedEventHandler(Object sender, ChangedEventArgs e);
public
event
ChangedEventHandler Changed;
//
declare a event.
protected
virtual
void
OnChanged(ChangedEventArgs e)
{
if
(Changed
!=
null
)
{
Changed(
this
, e);
}
}
public
void
Update(
string
userName)
{
ChangedEventArgs e
=
new
ChangedEventArgs(userName);
OnChanged(e);
}
}
}
You can see i define a Delegate variable and Event variable in the Trigger classs.
Please notice how to define the event frame. attention:
- The name of Delegate type must end by EventHandler.
- Definition of Delegate must have "void" return value, and it have two parameters, one is Object type, One is EventArgs type or implement of the EventArgs.
- The name of Event is remove the "EventHandler" from the name of Delegate.
- The name of Implement of the EventArgs should end by EventArgs.
How to register and remove the observer? we can use "+=" and "-=" to do it. please look the source code.