3.3 Observer Mode (OBSERVER)/publish-Subscribe mode
Motivation:
During the software build process, we need to establish a "notification dependency" for some objects-the state of an object (the target object) is changed, and all dependent objects (the Observer object) are notified. If such dependencies are too tight, the software will not be able to withstand changes very well.
Using object-oriented technology, you can weaken this dependency and form a stable dependency. So as to realize the loose coupling of software architecture.
code example: file splitter, adding process progress display.
The first method:
Parsing code: Violating the dependency inversion principle
Line 6th: ProgressBar as Implementation details (expression can be varied, shape interface, digital display, etc.). The role and task it plays is to inform.
The task to be notified is not implemented in a control way (too detail).
The second method: (refactoring the first kind)
Add the Iprogress class as an abstract notification mechanism, which is the Observer (subscriber). The observer contains an Update method Doprogress (). The specific observer (Mainform/consolenotifier) inherits the class and implements its own update function.
Filesplitter as the observed object (object/publisher), which contains an abstract notification mechanism iprogress pointers, using the Doprogress () method for notification.
That is, the object (publisher) does not have to consider the observer situation, automatic notification (release) work;
The Observer (subscriber) chooses whether to subscribe or how to handle notifications according to their actual situation.
Consider adding list<iprogress*> to multiple observer issues at the same time.
1//filesplitter1.cpp 2 class Filesplitter 3 {4 string m_filepath; 5 int m_filenumber; 6 progressbar* M_prog Ressbar; 7 8 Public:9 filesplitter (const string& filePath, int filenumber, progressbar* ProgressBar): M_filepa Th (FilePath), M_filenumber (FileNumber), M_progressbar (ProgressBar) {}15-void split () { 17 18//1. Read large files 19 20//2. Write to small files in batches for (int i = 0; i < M_filenumber; i++) {22//. .. float Progressvalue = m_filenumber;24 Progressvalue = (i + 1)/progressvalue;25 m_ Progressbar->setvalue (progressvalue);}27}29//MAINFORM1.CPP31 class Mainform:public Form32 {33 textbox* txtfilepath;34 textbox* txtfilenumber;35 progressbar* progressbar;36 notoginseng public:38 void Button1_C Lick () {max. String filePath = Txtfilepath->gettext (); int number = Atoi (Txtfilenumber->gettext (). C_str ()); 42Filesplitter Splitter (filePath, number, progressBar); Splitter.split (); 46 47}48};
The second method:
1//filesplitter2.cpp 2 class iprogress{3 public:4 virtual void doprogress (float value) =0; 5 Virtual ~iprogress () {} 6}; 7 8 9 class FileSplitter10 {one string m_filepath;12 int m_filenumber;13 list<iprogress*> M_iprogre Sslist; Abstract notification mechanism, support for multiple observers public:17 Filesplitter (const string& filePath, int filenumber): M_filepath (f Ilepath), M_filenumber (filenumber) {}22 () {25 26//1. Read large files 27 28// 2. Write to the small file in batches for (int i = 0; i < M_filenumber; i++) {30//... float Progressvalue = m_filenumber;33 Progressvalue = (i + 1)/progressvalue;34 OnProgress (Progressvalue)///Send notification}36 PNS}38 (addiprogress iprogress*) {IProgress Iprogresslist.push_back (iprogress),}43 iprogress* removeiprogress (iprogress m_iprogresslist) . Remove (iprogress);}47 protected:50 virtual void OnProgress (float value) {Wuyi List<iprogress*>::iterator itor=m_iprogresslist . Begin (); Itor! = M_iprogresslist.end ()) (*itor)->doprogress (value); Update progress bar itor++;57}58}59};60//mainform2.cpp62 class Mainform:public Form, public iprogre Ss63 {textbox* txtfilepath;65 textbox* txtfilenumber;66 (progressbar* progressbar;68) public:70 Voi D button1_click () {FilePath string = Txtfilepath->gettext (); int number = Atoi (txtfilenumber-> ; GetText (). C_STR ()); Consolenotifier cn;76 Filesplitter Splitter (filePath, number); Plitter.addiprogress (this); Subscription Notice splitter.addiprogress (&CN);//Subscription Notice Bayi splitter.split (); Splitter.removeiprogre SS (this);}87 doprogress (float value) {progressbar->setvalue (value); 90}91} ; clasS consolenotifier:public IProgress {94 public:95 virtual void Doprogress (float value) {cout << "."; 97}98};
Defined:
Defines a one-to-many (varying) dependency between objects so that when the state of an object (Subject) changes, all objects that depend on it are notified and updated automatically.
Class Diagram:
observer:iprogress; Update (): Doprogress ().
Concretesubject:filesplitter
Concreteobserver:mainform/consolenotifier
Depending on the standard observer schema definition, the addiprogress,removeprogress,onprogress can also be defined separately (Subject), and Filesplitter (ConcreteSubject) will inherit the class.
The above Method 2 is equivalent to combining subject and ConcreteSubject in the class diagram.
Summary of key points:
1. Using object-oriented abstraction, the Observer pattern allows us to independently change the target and the observer, thus making the dependencies between them loosely coupled.
2. When a target sends a notification, it is not necessary to specify the observer, and the notification will be automatically propagated (with the notification information as a parameter).
OnProgress (Progressvalue);//Send notifications without regard to specific observer issues.
3. The observer decides whether to subscribe to the notification, and the target object knows nothing about it.
Splitter.addiprogress (this); Subscribe to Notifications
Splitter.addiprogress (&CN);//Subscription notification
4.Observer mode is a very common design pattern in the event-based UI framework and is an important part of the MVC pattern.
C + + design mode 5 (observer/event observer mode)