1. Overview
Sometimes referred to as the Publish/subscribe pattern, the Observer pattern defines a one-to-many dependency that allows multiple observer objects to listen to a Subject object at the same time. This subject object notifies all observer objects when the state changes, enabling them to automatically update themselves.
2. Issues to solve
Splitting a system into a class in which some classes work together has a bad side effect, which is the need to maintain consistency among related objects. We do not want to be tightly coupled in order to maintain consistency, which can cause inconvenience to maintenance, expansion, and reuse. The observer is the solution to this kind of coupling relationship.
3. Roles in the pattern
3.1 Abstract Theme (Subject): It saves references to all observer objects in a single aggregation, each subject can have any number of observers. Abstract topics provide an interface that allows you to add and remove observer objects.
3.2 Specific topics (ConcreteSubject): deposit the relevant state into a specific observer object, and give notice to all registered observers when changes are made to the internal state of the specific subject.
3.3 Abstract Observer (Observer): Define an interface for all specific observers and update yourself when you get a topic notification.
3.4 Specific Observer (CONCRETEOBSERVER): Implements the update interface required by the abstract observer role in order to reconcile its 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> observers = new list<observer> (); <summary>///Add observers///</summary>//<param Name= "Observer" ></param> public void Attach (Observer Observer) {observers. ADD (Observer); }///<summary>//Remove observers///</summary>//<param Name= "Observer" ></par am> public void Detach (Observer Observer) {observers. REMOVE (Observer); }///<summary>///to the viewer///</summary> public void Notify () { foreach (Observer o in observers) {o.update (); }}}///<summary>///Abstract observer class, define an interface for all specific observers, update yourself when notified///</summary> public abstract Class Observer {public ABstract void Update (); }///<summary>///specific observers or individual notifier, the relevant status is deposited into the specific observer object, and all registered observers are notified when the internal state of the specific subject changes. A specific theme role is typically implemented with a specific subclass. </summary> public class Concretesubject:subject {private string subjectstate; <summary>///Specific observer status///</summary> public string Subjectstate { get {return subjectstate;} set {subjectstate = value;} }}////<summary>////Specific observers, implementing the update interface required by the abstract observer role, is already in harmony with the theme state/////</summary> public class Concre Teobserver:observer {private string observerstate; private string name; Private ConcreteSubject subject; <summary>////specific viewer with a specific theme to implement///</summary> public ConcreteSubject Subject { get {return subject;} set {subject = value;} } public Concreteobserver (ConcreteSubject subject, string name) {ThiS.subject = subject; THIS.name = name; }///<summary>//To implement update operations in the abstract Viewer///</summary> public override void Update () {observerstate = subject. 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 typically implemented with 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. Pattern Summary
5.1 Advantages
The 5.1.1 Observer pattern relieves the coupling between the subject and the specific observer, allowing both sides of the coupling to rely on abstraction, rather than relying on specifics. So that their changes will not affect the other side of the change.
5.2 Disadvantages
The 5.2.1 dependency is not completely lifted, and the abstract notifier still relies on the abstract observer.
5.3 Applicable Scenarios
5.3.1 when a change to an object needs to be changed to another object, and it does not know exactly how many objects are to be changed.
5.3.2 An abstract type has two aspects, when one aspect depends on another, then the observer pattern can be encapsulated in separate objects so that they are independently changed and reused.
6. Pattern extension, apply event delegation in C # to completely remove the coupling between the notifier and the Observer.
6.1 about the definition of a delegate: a delegate is a type that refers to a method. Once a delegate has been assigned a method, the delegate will have the same behavior as the method. A delegate method can have parameters and return values, just like any other method. A delegate can be thought of as an abstraction of a function (method), a "class" of a function, an instance of a delegate representing one (or more) specific functions, which can be multicast.
6.2 About events: events are based on delegates and provide a publish/subscribe mechanism for delegates. The subscription and cancellation of the event is similar to the subscription and cancellation in the Observer pattern we just talked about, except that the presentation is different. In observer mode, the subscription is done using method Attach (), and "+ =" is used in the subscription to the event. Similarly, the unsubscribe is used in observer mode with Dettach (), and the event is canceled with "-=".
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 the bookkeeping, the distribution clerk needs to match the goods.
7.2 Implementation of the Observer pattern
7.2.1 class Diagram
7.2.2 Code Implementation
<summary>///Abstract Viewer///</summary> public interface Isubject {void Notify (); }///<summary>///jobs as an observer here abstract///</summary> public abstract class Jobstation {p Ublic abstract void Update (); }///<summary>///specific theme, here is Customer///</summary> public class Customer:isubject {private String customerstate; Private ilist<jobstation> observers = new list<jobstation> (); <summary>///Add observers///</summary>//<param Name= "Observer" ></param> public void Attach (Jobstation observer) {THIS.OBSERVERS.ADD (Observer); }///<summary>//Remove observers///</summary>//<param Name= "Observer" ></par am> public void Detach (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 accountantstate; 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'm an accountant, I'll issue an invoice.") "); Accountantstate = "Invoiced"; }}}///<summary>//Cashier///</summary> public class Cashier:jobstation { private string cashierstate; Private customer customer; Public Cashier (Customer customer) {This.customer = customer; public override void Update () {if (customer. Customerstate = = "Paid") {Console.WriteLine ("I am a cashier, I register it.") "); Cashierstate = "recorded"; }}}///<summary>//distribution///</summary> public class Dilliveryman:jobstation { private string dillivierymanstate; Private customer customer; Public Dilliveryman (Customer customer) {This.customer = customer; public override void Update () {if (customer. Customerstate = = "Paid") {Console.WriteLine ("I am the delivery clerk, 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 (); } }
Operation Result:
I'm an accountant and I'm going to issue an invoice.
I'm a cashier and I'm checking in.
I'm the delivery clerk.
7.3 Event implementations
7.3.1 Class Diagram
In 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>//Declaration commissioned by///</summary> public delegate void Customereventhandler (); <summary>///specific topics///</summary> public class Customer:isubject {private string cus Tomerstate; Declares a delegate event of type Customereventhandler public event Customereventhandler Update; public void Notify () {if (Update! = null) {//Use event to notify subscriber UPD Ate (); }} public string Customerstate {get {return customerstate;} set {customerstate = value;} }}///<summary>//finance, no need to implement abstract observer classes, and do not refer to specific topics///</summary> public class Accountant { private string accountantstate; Public Accountant () {}//<summary>//Invoicing/</summary> public void Giveinvoice () {Console.WriteLine ("I'm an accountant, I'm going to issue an invoice.") "); Accountantstate = "Invoiced"; }}///<summary>//cashier, no need to implement abstract observer classes, and do not reference specific topics///</summary> public class Cashier { private string cashierstate; public void recoded () {Console.WriteLine ("I am a cashier, I register it.") "); Cashierstate = "recorded"; }}///<summary>///distribution, no need to implement abstract observer classes, and do not refer to specific topics///</summary> public class Dilliveryman {private string dillivierymanstate; public void Dilliver () {Console.WriteLine ("I am the delivery clerk, I come to deliver.") "); 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 notation can also be replaced with 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'm the delivery clerk.
Design Patterns Learning NOTES-observer patterns