[Gof Design Pattern]-Observer

Source: Internet
Author: User

I haven't updated my blog for about three months. I don't know what I am doing. I have always had a rule that I don't know when to start. To write a blog post, I have to write well. In each writing, I should summarize some of the previous writing methods to make up for some shortcomings, we also need to see progress. Therefore, I have made many attempts to write this article during the three months, but it is always affected by some things and the mood at the time. In order to pursue quality, I jumped to the present, sorry. The previous one-month commitment was not fulfilled and will be corrected later.

 

Well, back to the question, I should say sorry again when talking nonsense. ^_^. This article describes the Observer mode in GOF. The Observer mode should be regarded as one of the most widely used and influential design modes. Taking the latest work (FLASH version of MMORPG) For example, the development language is Action Script 3 and pureMVC is used, it is a lightweight MVC (Model/View/Control) framework. The Observer plays an important role in it. MVC decouples the business logic layer from the presentation layer. In addition, many systems use Observer and game development, such as the Ogre engine.

 

The observer mode can be simply understood as follows:

Publish-Subscribe (Publish/Subscribe)

Model-View (Model/View)

Source-Listener (Source/Listener)

Dependents)

 

Literally, I think you have a preliminary structure in your mind. Take the first form as an example. It distinguishes between publishers and subscribers. For example, if you subscribe to this blog, after this article is published, you will serve as a subscriber, will receive the update notification. From the publisher's perspective, he does not need to care who the subscriber is. As long as you subscribe, I will notify you. Subscribers do not need to come to this blog anytime to see if there are any updates (of course, this blog is always welcome to your visit ). In this way, everyone is relaxed, and there is a good relationship between cooperation and learning. Technically, you and I are loosely coupled.

 

For another example, we have all been to banks and now all banks provide dedicated queuing systems. This system has at least two advantages, one of the biggest advantages is that you don't have to stand in the queue or be afraid of those who don't say that order is not good or that they are not in the queue. Another advantage is that you don't have to pay attention to when it's your turn, because when you are there, the system will notify you through the display and voice. You can just sit in a cup of tea.

 

In these two examples, I don't need to show them in diagrams. I think you understand it. A very important part of brain image thinking is to outline obscure words into a picture in your mind. In this way, the ability to understand and learn abstract things is greatly improved.

 

Well, let's write a simple example. Let's take the introduction of publishing and subscription as an example to build a simple one-to-many relationship. The Code is as follows:

// Observer. h <br/> # ifndef _ observer_h __< br/> # DEFINE _ observer_h __</P> <p> # include <string> <br/> # include <list> </P> <p> class ipublisher; <br/> class isubscriber; </P> <p> typedef STD: String blog; <br/> typedef STD: List <isubscriber *> subscriberlist; </P> <p> // --------------------- subscriber --------------------- <br/> class isubscriber <br/>{< br/> Public: <br/> virtual ~ Isubscriber (void) {}; </P> <p> Public: <br/> virtual void Update (ipublisher * ppub) = 0; </P> <p> protected: <br/> isubscriber (void) {}; <br/>}; </P> <p> class subscriber_jack: Public isubscriber <br/>{< br/> public: <br/> subscriber_jack (void) {}; <br/> virtual ~ Subscriber_jack (void) {}; </P> <p> Public: <br/> void Update (ipublisher * ppub); <br/> }; </P> <p> class subscriber_sam: Public isubscriber <br/>{< br/> Public: <br/> subscriber_sam (void) {}; <br/> virtual ~ Subscriber_sam (void) {}; </P> <p> Public: <br/> void Update (ipublisher * ppub); <br/> }; </P> <p> // --------------------- publisher --------------------- <br/> class ipublisher <br/>{< br/> Public: <br/> virtual ~ Ipublisher (void) {}; </P> <p> Public: <br/> virtual void subscribe (isubscriber * psub ); <br/> virtual void unsubscribe (isubscriber * psub); <br/> virtual void publish (Blog & blog); </P> <p> virtual Blog & getblog (void) = 0; </P> <p> protected: <br/> ipublisher (void) {}; <br/> virtual void setblog (Blog & blog) = 0; </P> <p> PRIVATE: <br/> subscriberlist m_sublist; <br/>}; </P> <p> class publisher_mas: Pub LIC ipublisher <br/>{< br/> Public: <br/> publisher_mas (void) {}; <br/> ~ Publisher_mas (void) {}; </P> <p> Public: <br/> Blog & getblog (void); </P> <p> protected: <br/> void setblog (Blog & blog); </P> <p> PRIVATE: <br/> blog m_blog; <br/> }; </P> <p> # endif

This header file defines two interface classes: ipublisher and isubscriber, which are used to represent the publisher and subscriber. Two Actual subscriber classes and one publisher class are defined: subscriber_jack, subscriber_sam, and publisher_mas. Publisher_mas publishes a blog post. subscriber_jack and subscriber_sam receive update notifications. The specific implementation is as follows:

// Observer. CPP <br/> # include <iostream> <br/> # include "Observer. H "</P> <p> void subscriber_jack: Update (ipublisher * ppub) <br/>{< br/> STD: cout <" subscriber_jack: "<ppub-> getblog () <STD: Endl; <br/>}</P> <p> void subscriber_sam: Update (ipublisher * ppub) <br/> {<br/> STD: cout <"subscriber_sam:" <ppub-> getblog () <STD: Endl; <br/>}</P> <p> void ipublisher: Subscribe (isubscriber * psub) <Br/>{< br/> m_sublist.push_front (psub); <br/>}</P> <p> void ipublisher: Unsubscribe (isubscriber * psub) <br/>{< br/> If (psub! = NULL) <br/>{< br/> subscriberlist: iterator it = m_sublist.begin (); <br/> subscriberlist: iterator end = m_sublist.end (); <br/> while (it! = END) <br/>{< br/> If (* It) = psub) <br/>{< br/> m_sublist.remove (psub ); <br/> break; <br/>}< br/> ++ it; <br/>}</P> <p> void ipublisher: publish (Blog & blog) <br/>{ <br/> setblog (blog); <br/> subscriberlist: iterator it = m_sublist.begin (); <br/> subscriberlist :: iterator end = m_sublist.end (); <br/> while (it! = END) <br/> (* It ++)-> Update (this); <br/>}</P> <p> void publisher_mas :: setblog (Blog & blog) <br/>{< br/> m_blog = blog; <br/>}</P> <p> Blog & publisher_mas: getblog (void) <br/>{< br/> return m_blog; <br/>}< br/>

Therefore, an observation and observation mode is formed. When a blog post needs to be published, publisher_mas can be used to send the blog update notification to every subscriber. The code is very simple, let's look at how to use it:

// Main. CPP <br/> # include "Observer. H "</P> <p> int main (void) <br/> {<br/> publisher_mas * masemas = new publisher_mas (); </P> <p> subscriber_jack * Jack = new subscriber_jack (); <br/> subscriber_sam * Sam = new subscriber_sam (); </P> <p> masebe-> subscribe (Jack); <br/> masebe-> subscribe (SAM ); </P> <p> blog = "[gof design mode] -- Observer"; <br/> maseish-> Publish (blog ); </P> <p> masebe-> unsubscribe (Jack); <br/> masebe-> unsubscribe (SAM); </P> <p> Delete Jack; <br/> Delete Sam; <br/> Delete masetasks; </P> <p> return 0; <br/>}

Output result:

Subscriber_sam: [gof design mode] -- Observer
Subscriber_jack: [path to the gof design mode] -- Observer

 

This example is just a simple example. The robustness is not taken into consideration. The whole model is clearly defined and more things are added, but the details may be ignored. The principles are implemented using lightweight code whenever possible. The above code can be expressed in a simple illustration, 1:

 Figure 1 Observer Mode

 

During update, a publisher parameter is transmitted to each subscriber. This parameter allows the subscriber to subscribe to multiple publishers at the same time. Of course, it can also be implemented in other forms. In practice, it should be handled flexibly. The design model only provides our ideas and does not strictly stipulate certain forms to follow.

 

In ogre, a typical example is framelistener. In addition, keyboard and mouse events are often implemented through Observer, such as keylistener and mouselistener. This form is similar to the above example. You can say that you only change the name. The lisenter here is equivalent to the subscriber. It inherits from the abstract listener above. Then there can be a manager similar to listenermanager for dispatch and register. The principle is almost the same, so I will not detail it here.

 

At this moment, according to the observer format described above, I think of a process-oriented language like C. If there is no class in C language, there will be no inheritance. What should I do if I want to implement the observer mode? So I wrote some code for reference:

# Include <stdio. h> <br/> # include <string. h> </P> <p> # pragma warning (Disable: 4996) </P> <p> # define max_listeners 20 <br/> typedef int (* listener) (void *); </P> <p> listener listeners [max_listeners]; </P> <p> typedef struct _ publisher <br/> {<br/> char publisher [16]; <br/> char name [256]; <br/>} publisher; </P> <p> void registerlistener (listener listen) <br/>{< br/> int I; <br/> for (I = 0; I <Max _ Listeners; ++ I) <br/>{< br/> If (listeners [I] = NULL) <br/>{< br/> listeners [I] = listen; <br/> break; <br/>}</P> <p> void unregisterlistener (listener listen) <br/>{< br/> int I; <br/> for (I = 0; I <max_listeners; ++ I) <br/> {<br/> If (listeners [I] = listen) <br/>{< br/> listeners [I] = NULL; <br/> break; <br/>}</P> <p> void DISPATCHER (publisher * P) <br/>{< br/> int I; <br/> for (I = 0; I <max_listeners; ++ I) <br/>{< br/> If (listeners [I]! = NULL &&! Listeners [I] (p) <br/> break; <br/>}</P> <p> int listener1 (publisher * P) <br/>{< br/> printf ("listener1: % s-% s/n", p-> publisher, p-> name ); <br/> return 1; <br/>}</P> <p> int listener2 (publisher * P) <br/>{< br/> printf ("listener2: % s-% s/n ", p-> publisher, p-> name); <br/> return 1; <br/>}</P> <p> int main (void) <br/>{< br/> publisher blog; <br/> strcpy (blog. publisher, "maseher"); <br/> strcpy (blog. name, "[gof Design Pattern path] -- Observer"); </P> <p> registerlistener (listener1); <br/> registerlistener (listener2 ); </P> <p> DISPATCHER (& blog); </P> <p> printf ("/N"); <br/> unregisterlistener (listener1 ); </P> <p> DISPATCHER (& blog); </P> <p> return 0; <br/>}

Output result:

Listener1: masefee-[path to the gof design mode] -- Observer
Listener2: masefee-[path to the gof design mode] -- Observer

 

Listener2: masefee-[path to the gof design mode] -- Observer

 

The above is listen by registering the callback function, and the distributor dispatcher is responsible for distributing it to each callback function. The callback function also has the function of decoupling. The caller has no need to know who the caller is. In the above example, a global array is used, and a data structure such as list linked list can be implemented to store the callback function. Of course, it seems a bit nondescribable here, but it is often used in practice. In that case, there is no strict constraint on the design model, and we can handle it flexibly, the design mode is just a method and an idea. Therefore, you can use the language either process-oriented or object-oriented. Besides, object-oriented is not a patent of object-oriented languages, and it is also an idea. Applicable to any type of programming language. Therefore, in this example, the observer in C language is also true. In practice, you can flexibly customize the design as needed.

 

As shown in the C language example above, a more vivid graph can be used as follows:

Figure 2 listener form of observer

 

Summary:

This article is almost the same, observer is not difficult, it is mainly used for independent changes and reuse between objects, that is, to reduce coupling. It is also used when an object needs to be changed, but it does not know how many objects will change. This also reflects loose coupling. Therefore, when you do not need to closely connect some objects and meet the first two requirements, you can consider using observer. Finally, it is explained again that the design pattern is only a method and an idea, not a constraint. When learning and using it, we should focus on flexible response. We can't remember it like a piece of money, so you have enough divergent brains to stay at home.

 

Well, this article ends here, because of my limited level, all the above content is for reference only, and you are welcome to make a brick, I have only one purpose, continue to improve !!

 

[Gof Design Pattern path] Directory

[Gof Design Pattern] -- Opening

[Gof Design Pattern] -- Singleton

[Gof Design Pattern path] -- Factory

[Gof Design Pattern] -- Observer

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.