Solved problems:
We bought several abstract paintings when decorating our new home. After buying them, we found that some colored borders are more suitable for us, while some of them are more suitable for our use. How can we solve this problem? He needs to dynamically add additional responsibilities to other objects, which is the purpose of the Paster mode.
We can add new functions to the original object by means of inheritance, but the decoration mode is more flexible than the subclass generation by means of combination.
Class chart and sample implementation:
In the decoration mode, the roles are:
Abstract component role: provides an abstract interface to standardize the objects that are prepared to receive additional responsibilities.
Concrete component role: defines a class that will receive additional responsibilities.
Decorator: holds an instance of a component object and defines an interface consistent with the abstract Component Interface.
Concrete decorator: attaches "additional responsibilities to the component object.
[CPP]View plaincopy
- # Include <string>
- # Include <iostream>
- # Include <memory>
- Using namespace STD;
- // Abstract class Tank
- Class Tank
- {
- Public:
- Virtual void shot () = 0;
- Virtual void run () = 0;
- Public:
- Virtual ~ Tank ()
- {
- Cout <"in the destructor of Tank" <Endl;
- }
- };
- // Specific class T50
- Class T50: Public Tank
- {
- Public:
- Void shot ()
- {
- Cout <"tank T50 shot ()" <Endl;
- }
- Void run ()
- {
- Cout <"tank T50 run ()" <Endl;
- }
- Public:
- Virtual ~ T50 ()
- {
- Cout <"in the destructor of T50" <Endl;
- }
- };
- // Specific class T75
- Class T75: Public Tank
- {
- Public:
- Void shot ()
- {
- Cout <"tank T75 shot ()" <Endl;
- }
- Void run ()
- {
- Cout <"tank T75 run ()" <Endl;
- }
- Public:
- Virtual ~ T75 ()
- {
- Cout <"in the destructor of T75" <Endl;
- }
- };
- // Abstract class, decorator
- Class decorator: Public Tank
- {
- Protected:
- Tank * tank;
- Public:
- Decorator (tank * tank): tank (tank) {}// decoration class of the specific tank
- Virtual ~ Decorator ()
- {
- Cout <"in the destructor of decorator" <Endl;
- }
- Public:
- Void shot ()
- {
- Tank-> shot ();
- }
- Void run ()
- {
- Tank-> Run ();
- }
- };
- Class infrareddecorator: Public decorator
- {
- PRIVATE:
- String infrared; // This is the so-called addatrried
- Public:
- Infrareddecorator (tank * tank): decorator (tank ){}
- Virtual ~ Infrareddecorator ()
- {
- Cout <"in the destructor of infrareddecorator" <Endl;
- }
- Public:
- Void set_infrared (const string & infrared)
- {
- This-> infrared = infrared;
- }
- String get_infrared () const
- {
- Return infrared;
- }
- Void run ()
- {
- Tank-> Run ();
- Set_infrared ("+ infrared ");
- Cout <get_infrared () <Endl;
- }
- Void shot ()
- {
- Tank-> shot ();
- }
- };
- Class amphibiandecorator: Public decorator
- {
- PRIVATE:
- String amphibian;
- Public:
- Amphibiandecorator (tank * tank): decorator (tank ){}
- ~ Amphibiandecorator ()
- {
- Cout <"in the destructor of amphibiandecorator" <Endl;
- }
- Public:
- Void set_amphibian (const string & hibian)
- {
- This-> amphibian = hibian;
- }
- String get_amphibian () const
- {
- Return amphibian;
- }
- Public:
- Void run ()
- {
- Tank-> Run ();
- Set_amphibian ("+ amphibian ");
- Cout <get_amphibian () <Endl;
- }
- Void shot ()
- {
- Tank-> shot ();
- }
- };
- Int main (INT argc, char ** argv)
- {
- // Adds the infrared function to the t50.
- Tank * tank1 (New T50 );
- Tank * pid1 (New infrareddecorator (tank1 ));
- Pid1-> shot ();
- Cout <Endl;
- Pid1-> Run ();
- Cout <Endl;
- Cout <Endl <"---------------" <Endl;
- // Adds infrared and amphibious functions to T75
- Tank * tank2 (New T75 );
- Tank2-> Run ();
- Tank * pid2 (New infrareddecorator (tank2 ));
- Tank * pad2 (New amphibiandecorator (pid2 ));
- Pad2-> shot ();
- Cout <Endl;
- Pad2-> Run ();
- Cout <Endl;
- Cout <Endl <"--------------" <Endl;
- // Dynamically undo other decorations?
- Tank2-> Run ();
- Tank * tank3 (tank2 );
- Tank3-> Run ();
- Return 0;
- }
Differences between the modifier and the adapter:
1. About new responsibilities: the adapter can also add new responsibilities during the conversion, but the main purpose is not here. The decorator mode adds new responsibilities to the decorator.
2. Original interface: the adapter mode uses a new interface to call the original interface. The original interface is invisible or unavailable to the new system. The original interface is used in the decoration mode, and the system also uses the original interface for the decoration objects. (The modifier mode for adding new interfaces can be considered as its variant-"Translucent" modifier)
3. About the object of the package: the adapter knows the details of the adapter (that is, the class or the interface ). The decorator only knows what its interface is. The specific type (whether it is a base class or another derived class) is only known during running.
Key points:
1. the decorator and the decorated object have the same super type.
2. One or more decorators can wrap an object.
3. the decorator Can add his/her own actions before or after the actions of the entrusted decorator to achieve a specific purpose.
4. objects can be decorated at any time, so they can be dynamically decorated at runtime. You can use your favorite decorator to decorate objects in an unlimited number.
5. In the decoration mode, the key to inheritance is to match the type of the modifier and the decorated object, rather than obtaining its behavior.
6. the decorator is generally transparent to the customer of the component, unless the customer program depends on the specific type of the component. In actual projects, you can add new behaviors to the decorator as needed to achieve "Translucent.
Applicable scenarios and advantages and disadvantages: The decoration mode should be used in the following situations:
1. You need to extend the functions of a class or add additional responsibilities to a class.
2. You need to dynamically add functions to an object. These functions can be dynamically revoked.
3. A large number of functions are generated by the arrangement and combination of some basic functions to make the inheritance relationship unrealistic.
Advantages:
1. The purpose of the decorator mode and the inheritance relationship is to expand the object functions, but the decorator can provide more flexibility than inheritance.
2. By using different specific decorative classes and the arrangement and combination of these decorative classes, designers can create a combination of many different behaviors.
Disadvantages:
1. This is more flexible than inheritance, and it also means more complexity.
2. The decoration mode will lead to many small classes in the design. Excessive use will complicate the program.
3. The decoration mode is designed for the component type. However, if you want to program specific components, you should rethink your application architecture and whether the decorator is appropriate. Of course, you can also change the Component Interface, add new public behavior, and implement the "Translucent" modifier mode. Make the best choice in the actual project.