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.cpp2 classFilesplitter3 {4 stringM_filepath;5 intM_filenumber;6progressbar*M_progressbar;7 8 Public:9Filesplitter (Const string& FilePath,intFileNumber, progressbar*ProgressBar):Ten M_filepath (FilePath), One M_filenumber (filenumber), A M_progressbar (progressBar) { - - } the - voidsplit () { - - //1. Read large files + - //2. Write to small files in batches + for(inti =0; i < M_filenumber; i++){ A //... at floatProgressvalue =M_filenumber; -Progressvalue = (i +1) /Progressvalue; -M_progressbar->SetValue (progressvalue); - } - - } in - //MainForm1.cpp to classMainForm: PublicForm + { -textbox*Txtfilepath; thetextbox*Txtfilenumber; *progressbar*ProgressBar; $ Panax Notoginseng Public: - voidbutton1_click () { the + stringFilePath = txtfilepath->GetText (); A intNumber = Atoi (txtfilenumber->GetText (). C_STR ()); the + Filesplitter Splitter (filePath, number, progressBar); - $ splitter.split (); $ - } -};
The second method:
1 //FileSplitter2.cpp2 classiprogress{3 Public:4 Virtual voidDoprogress (floatValue) =0;5 Virtual~IProgress () {}6 };7 8 9 classFilesplitterTen { One stringM_filepath; A intM_filenumber; - -List<iprogress*> m_iprogresslist;//Abstract notification mechanism to support multiple observers the - Public: -Filesplitter (Const string& FilePath,intfilenumber): - M_filepath (FilePath), + M_filenumber (filenumber) { - + } A at - voidsplit () { - - //1. Read large files - - //2. Write to small files in batches in for(inti =0; i < M_filenumber; i++){ - //... to + floatProgressvalue =M_filenumber; -Progressvalue = (i +1) /Progressvalue; theOnProgress (Progressvalue);//Send Notifications * } $ Panax Notoginseng } - the + voidAddiprogress (iprogress*iprogress) { A M_iprogresslist.push_back (iprogress); the } + - voidRemoveiprogress (iprogress*iprogress) { $ M_iprogresslist.remove (iprogress); $ } - - the protected: - Virtual voidOnProgress (floatvalue) {Wuyi theList<iprogress*>::iterator itor=M_iprogresslist.begin (); - Wu while(Itor! =m_iprogresslist.end ()) -(*itor)->doprogress (value);//Update progress bar Aboutitor++; $ } - } - }; - A //MainForm2.cpp + classMainForm: PublicForm, PublicIProgress the { -textbox*Txtfilepath; $textbox*Txtfilenumber; the theprogressbar*ProgressBar; the the Public: - voidbutton1_click () { in the stringFilePath = txtfilepath->GetText (); the intNumber = Atoi (txtfilenumber->GetText (). C_STR ()); About the Consolenotifier cn; the the Filesplitter Splitter (filePath, number); + -Splitter.addiprogress ( This);//Subscribe to Notifications theSplitter.addiprogress (&CN);//Subscribe to NotificationsBayi the splitter.split (); the -Splitter.removeiprogress ( This); - the } the the Virtual voidDoprogress (floatvalue) { theProgressbar->SetValue (value); - } the }; the the classConsolenotifier: PublicIProgress {94 Public: the Virtual voidDoprogress (floatvalue) { thecout <<"."; the }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)