1. Overview
Sometimes referred to as the Publish/subscribe model, the Observer pattern defines a one-to-many dependency that allows multiple observer objects to simultaneously listen to a Subject object. When the state changes, the subject object notifies all the observer objects so that they can automatically update themselves.
2. The problem addressed
Splitting a system into classes that collaborate with one another has a bad side-effect of maintaining consistency among related objects. We don't want to keep all kinds of tight coupling in order to maintain consistency, which can be inconvenient for maintenance, expansion, and reuse. The observer is the solution to this kind of coupling relationship.
3. Role in the pattern
3.1 Abstract Theme (Subject): It saves the references of all the observer objects to a cluster, each subject can have any number of observers. Abstract topics provide an interface for adding and deleting observer objects.
3.2 Specific Theme (ConcreteSubject): Deposit the State of a specific observer object and give notice to all registered observers when the internal state of the specific subject changes.
3.3 Abstract Observer (Observer): Defines an interface for all specific observers, updating themselves when the subject is notified.
3.4 Specific Observer (CONCRETEOBSERVER): Implements the update interface required by the abstract observer role to reconcile its own state with the subject state.
4. Pattern Interpretation
4.1 Class diagram of the Observer pattern
4.2 Code for the Observer pattern
<summary>///Abstract Subject class///</summary> public abstract class Subject {private ilist<observer> OB
Servers = new list<observer> (); <summary>///Add observer///</summary>///<param name= "Observer" ></param> public void Attach ( Observer Observer) {observers.
ADD (Observer); ///<summary>///Removal observer///</summary>///<param name= "Observer" ></param> public void Det Ach (Observer Observer) {observers.
REMOVE (Observer); ///<summary>///notifies observers///</summary> public void Notify () {foreach (Observer o in observers
) {o.update ();
}}///<summary>///Abstract Observer class, define an interface for all specific observers, and update themselves when notified///</summary> public abstract class Observer
{public abstract void Update (); ///<summary>///A specific observer or specific notification, the State is deposited with the specific observer object, and all registered observers are notified when the internal state of the specific subject changes.
Specific theme roles are usually implemented with a specific subclass. </summary> public class Concretesubject:subject {private stringSubjectstate;
<summary>///The state of the specific observer///</summary> public string Subjectstate {get {return subjectstate;}
set {subjectstate = value;} }///<summary>///specific observers to implement the update interface required by the abstract observer role, which is already in harmony with the state of the topic///</summary> public class Concreteobserve
R:observer {private string observerstate;
private string name;
Private ConcreteSubject subject; <summary>///The specific observer uses a specific theme to implement///</summary> public ConcreteSubject Subject {got {return Subject;
set {subject = value;}
Public Concreteobserver (concretesubject subject, string name) {this.subject = subject;
THIS.name = name; ///<summary>///Implement update operations in abstract observers///</summary> public override void Update () {observerstate = Subje Ct.
Subjectstate;
Console.WriteLine ("The Observer ' s state of {0} is {1}", name, observerstate); }
}
4.3 Client code
Class program
{
static void Main (string[] args)
{
//specific theme roles are usually implemented in a specific
concretesubject subject = New ConcreteSubject ();
Subject. Attach (New Concreteobserver (Subject, "Observer A"));
Subject. Attach (New Concreteobserver (Subject, "Observer B"));
Subject. Attach (New Concreteobserver (Subject, "Observer C"));
Subject. Subjectstate = "Ready";
Subject. Notify ();
Console.read ();
}
Run results
5. Model Summary
5.1 Advantages
The 5.1.1 Observer model relieves the coupling between the subject and the specific observer, allowing both sides of the coupling to rely on abstraction rather than reliance on concrete. So that their changes will not affect the other side of the change.
5.2 Disadvantages
5.2.1 dependencies are not completely lifted, and abstract notifications are still dependent on abstract observers.
5.3 Applicable Scenarios
5.3.1 When a change of an object needs to be changed to another object, and it does not know how many objects are to be changed.
5.3.2 An abstract type has two aspects, and when one aspect relies on another, the observer pattern allows the two to be encapsulated in separate objects so that they can be changed and reused independently.
6. Pattern extension, apply the event delegates in C # to completely remove the coupling between the notification and the observer.
6.1 about the definition of a delegate: a delegate is a type of reference method. Once a method is assigned to a delegate, the delegate behaves the same way as the method. A delegate method can have parameters and return values, like any other method. A delegate can be seen as an abstraction of a function (method), a "class" of functions, an instance of a delegate representing one (or more) specific function, which can be multicast.
6.2 About events: events are based on delegates, providing a publish/subscribe mechanism for delegates. The subscription and cancellation of events are similar to those in the Observer mode we just talked about, except that the representations are different. In observer mode, subscriptions are made using method Attach (), and "+ =" is used in subscriptions to events. Similarly, unsubscribe is used Dettach () in observer mode, and the cancellation of the event is "=".
7. The following examples are implemented using the Observer pattern, the event mechanism, respectively
7.1 Example Description: The customer pays the order money, then the finance needs to issue the invoice, the cashier needs to record, the distribution clerk needs to supply the goods.
7.2 Implementation of the Observer model
7.2.1 class Diagram
7.2.2 Code Implementation
<summary>///Abstract Observer///</summary> public interface Isubject {void Notify (); ///<summary>///Jobs, as the observer of the abstract///</summary> public abstract class Jobstation {public abstract
void Update (); ///<summary>///Specific topic, here is Customer///</summary> public class Customer:isubject {private String custome
Rstate;
Private ilist<jobstation> observers = new list<jobstation> (); <summary>///Add observer///</summary>///<param name= "Observer" ></param> public void Attach (
Jobstation observer) {THIS.OBSERVERS.ADD (Observer); ///<summary>///Removal observer///</summary>///<param name= "Observer" ></param> public void Det
ACH (jobstation observer) {THIS.OBSERVERS.REMOVE (Observer);
///<summary>///Customer status///</summary> public string Customerstate {get {return customerstate;}
set {customerstate = value;} public void Notify () {forEach (Jobstation o in observers) {o.update (); }}///<summary>///accounting///</summary> public class Accountant:jobstation {private String Accou
Ntantstate;
Private customer customer;
Public Accountant (Customer customer) {This.customer = customer; ///<summary>///Update status///</summary> public override void Update () {if (customer). Customerstate = = "Paid") {Console.WriteLine ("I am an accountant, I will issue an invoice.")
");
Accountantstate = "Invoiced"; }}///<summary>///cashier///</summary> public class Cashier:jobstation {private string cashiers
Tate
Private customer customer;
Public Cashier (Customer customer) {This.customer = customer; public override void Update () {if (customer). Customerstate = = "Paid") {Console.WriteLine ("I'm a cashier, I'm checking in.")
");
Cashierstate = "recorded"; }}///<summary>///distribution Clerk///</summary> public class Dilliveryman:jobstation {private string di
Llivierymanstate; PrivaTe customer customer;
Public Dilliveryman (Customer customer) {This.customer = customer; public override void Update () {if (customer). Customerstate = = "Paid") {Console.WriteLine ("I am a distributor, I come to deliver.")
");
Dillivierymanstate = "Shipped";
}
}
}
7.2.3 Client Code
Class program
{
static void Main (string[] args)
{
Customer subject = new Customer ();
Subject. Attach (new Accountant (subject));
Subject. Attach (new Cashier (subject));
Subject. Attach (new Dilliveryman (subject));
Subject. Customerstate = "Paid";
Subject. Notify ();
Console.read ();
}
Run Result:
I'm an accountant and I'm going to issue an invoice.
I'm a cashier and I'm checking in.
I am a distributor and I will deliver the goods.
7.3 Event Implementation
7.3.1 Class Diagram
From the class diagram, there is no dependency between the observer and the subject.
7.3.2 Code Implementation
<summary>///Abstract Theme///</summary> public interface Isubject {void Notify ();
///<summary>///declares the delegate///</summary> public delegate void Customereventhandler ();
<summary>///Specific Subject///</summary> public class Customer:isubject {private string customerstate;
Declares a delegate event with the type Customereventhandler public event Customereventhandler Update;
public void Notify () {if (update!= null) {///Use event to notify subscriber Update ();
} public string Customerstate {get {customerstate;}
set {customerstate = value;} }///<summary>///Finance, there is no need to implement abstract observer classes, and do not refer to specific topics///</summary> public class Accountant {private S
Tring Accountantstate; Public Accountant () {}///<summary>///development ticket///</summary> public void Giveinvoice () {Console.writ Eline ("I am an accountant, I will issue an invoice.")
");
Accountantstate = "Invoiced";
}///<summary>///cashier, there is no need to implement abstract observer classes, and not to refer to specific topics///</summary>public class Cashier {private string cashierstate; public void recoded () {Console.WriteLine ("I'm a cashier, I'm checking in.")
");
Cashierstate = "recorded"; }///<summary>///, there is no need to implement abstract observer classes and do not refer to specific topics///</summary> public class Dilliveryman {privat
E string dillivierymanstate; public void Dilliver () {Console.WriteLine ("I am a distributor, I am shipping.")
");
Dillivierymanstate = "Shipped";
}
}
7.3.3 Client Code
Class program
{
static void Main (string[] args)
{
Customer subject = new Customer ();
Accountant Accountant = new Accountant ();
Cashier cashier = new cashier ();
Dilliveryman Dilliveryman = new Dilliveryman ();
Register Event
subject. Update + = Accountant. Giveinvoice;
Subject. Update + = Cashier. recoded;
Subject. Update + = Dilliveryman. Dilliver;
* * The above wording can also be replaced by the following code
subject. Update + = new Customereventhandler (accountant. Giveinvoice);
Subject. Update + = new Customereventhandler (cashier. recoded);
Subject. Update + = new Customereventhandler (Dilliveryman. Dilliver);
* *
subject. Customerstate = "Paid";
Subject. Notify ();
Console.read ();
}
Run results
I'm an accountant and I'm going to issue an invoice.
I'm a cashier and I'm checking in.
I am a distributor and I will deliver the goods.