Decoration mode:
1. the decorator can add a new behavior before or after the behavior to be decorated, or even completely replace it.
2. decorator may produce many small objects and cannot be used excessively.
3. By combining and entrusting, You can dynamically add new behaviors at runtime.
4. the modifier mode follows the principle of extended and open, and modified and closed.
5. the decorator mode packs the decorator in combination to expand the decorator.
Decorator of The Real World:
Java. io class. Added features through layer-by-layer packaging
Basic Architecture:
An abstract class has some basic units (specific classes) and some basic decorative factors. By combining basic units and decorative factors, you can form complex units. At the same time, complex units can be decorated again, making the functions more powerful. All basic units and decorated complex units are inherited from an abstract class to unify the types. This reminds us of the combined mode and MacroCommand used in the command mode described in the previous section.
Macro commands are the embodiment of a combination mode, and the decoration here is also the embodiment of a combination mode. The macro command contains a linked list that stores the set of commands. The modifier focuses more on the decoration of a certain unit, therefore, for the modifier class, you only need to pass an abstract class pointer, and the macro command is a command set. The decorator emphasizes adding new features to the existing things, and the macro command emphasizes that the functions are merged to form a function list. The modifier generally adds a new method to expand the function of an existing unit. Macro commands generally directly call the action of a bunch of commands, encapsulate a bunch of commands into a single command. Similar to macro commands, there are directory tree structures, typical combination mode ideas, and the class graph structure in observer mode when the Subject is also the observer.
Decoration mode:
Big traps and small circles, one by one.
Combination Mode:
Small circles and large circles.
// Base class abstract class. Class Light {public: Light () {}public: virtual string GetInfo () = 0 ;}; // basic unit BulbLight, BulbLight, they may need to expand new functions later class BulbLight: public Light {public: BulbLight () {}publc: string GetInfo () {return "BulbLight ";}}; // basic unit LampLight, incandescent class LampLight: public Light {public: LampLight () {}publc: string GetInfo () {return "LampLight ";}}; // The decoration factor is as follows // Add the color-based function class ColorLight: public Light {public: ColorLight (Light * light) {thi S-> m_pLight = light;} public: string GetInfo () {return m_pLight-> GetInfo () + "Color";} private: Light * m_pLight ;}; // added the flashing function class BlinkLight: public Light {public: BlinkLight (Light * light) {this-> m_pLight = light;} public: string GetInfo () {return m_pLight-> GetInfo () + "Blink" ;}}// added the VoiceLight class: public Light {public: VoiceLight (Light * light) {this-> m_pLight = light;} public: string GetInfo () {return m _ PLight-> GetInfo () + "Voice" ;}// you can combine the basic unit and decorative factor to form a powerful lamp. // For example, create a flashlight BulbLight * pLight = new BulbLight; BlinkLight * pBlink = new BlinkLight (pLight); VoiceLight * pVoiceBlink = new VoiceLight (pBlink ); cout <pVoiceBlink-> GetInfo () <endl;
The modifier mode is just like its name. It is mainly used to add some new functions to the existing class without affecting the original interface. Generally, there is an abstract class. For example, the Light above is an abstract of a lamp. It has a function called GetInfo, because it is abstract, therefore, methods like this are also defined as virtual functions, so that sub-classes can be customized. BulbLight and LampLight are specific lamp classes. They have their own GetInfo functions, but now the demand is increased and the BulbLight for sound control is required. Here, we have two solutions: one is to inherit from BulbLight, add the voice control function, and then call the basic GetInfo method of BulbLight. The other is to use the above similar method, inheriting from the abstract Light, the BulbLight that will add the voice control function will be passed in, while the GetInfo interface will remain unchanged. The original functions will be reused in combination and new functions will be added.
Analysis:
Advantages and disadvantages of inheritance and combination: If you want to create a flashing BulbLight with sound control function, you will find that inheritance has its limitations. Through combination, you can add any functions you want to add to existing functions without restrictions. Through inheritance, when you only add one function, you still can't see the problem. After all, an inheritance is done. When the function is gradually added, the inheritance level of your class will gradually increase, in addition, when the features a and B and c are required at the same time, do we still need to carry out multiple inheritance? The more you expand, the more limited you are. This obviously violates the principle of openness to expansion.
Superior decoration mode:
This mode completes its tasks by combining them. In order to maintain the uniformity of the Code interfaces, the classes of new functions are also inherited from the Light abstract class and related interfaces are implemented; in order to add functions to existing classes, the existing class objects are passed in, and their old functions are called through combined delegation, you can add new functions to the code.
Basic class structure:
Class Abstract {virtual void BasicFunction () = 0; // basic functions}; Class OldConcrete: public Abstract {void BasicFunction () {// basic functions //.... previous Basic Function Code }}; // used in the past: Abstract * pConcrete = new OldConcrete (); pConcrete. basicFunction (); // new requirements are coming, and existing functions need to be extended. Class NewConcrete: public Abstract // In order to ensure unified interfaces and interface-oriented programming, it inherits from the Abstract base Class {public: NewConcrete (Abstract * pA) {this. m_pA = pA;} public: void BasicFunction () {// 1. Assume that you need to call the old function m_pA-> BasicFunction (); // 2 to call new extended functions, in this way, the new function ExtendFunction ();} private: void ExtendFunction () {// code for the New Extended Function} private: abstract * m_pA ;}; // current usage: Abstract * pConcrete = new OldConcrete (); Abstract * pNewConcrete = NewConcrete (pConcrete); // only required Repackage pNewConcrete. BasicFunction (); // do not change the interface. If the old OldConcrete does not change, it will secretly add new functions.