"Decorator", also known as "Wrapper )",It is usually used to flexibly expand object functions..
Before that, we can extend the function of the parent class through class inheritance. However, this inheritance method lacks flexibility and will quickly expand the number of child classes. By using the decoration mode properly, we can flexibly extend object functions on the basis of controlling the number of child classes. The decoration mode is more flexible than class inheritance.
Example:
1. Wall Painting (Terrylee example ):A painting can be mounted on the wall, but we usually put it in a frame, covered with glass, and then mounted on the wall. The frame and glass here are the decoration of the painting. After being decorated, it becomes an object, and then the frame is actually mounted on the wall.
2. Pig escape game:A pig and a gray wolf have a maximum of five lives. Each time the wolf bites the pig, the pig will lose one life. The task of the pig is to escape the pig's pursuit of the pig. During the process of escaping, Small and Medium pig can eat three kinds of apples. Eating "Red Apple" can add protective covers to pig, and eating "green apple" can speed up pig running, eating "yellow apple" can make pig catch water. If pig eats a variety of apples, pig can have a variety of functions provided by Apple.
In this example, if we use class inheritance to implement it, it will be troublesome. You need to derive 3*2*1 = 6 sub-classes for pig (pig with protective cover, the fast-running pig has the ability to flat the pigs with water, the pigs with water shield and water, the fast-running pig with water shield and the fast-running pig, pig with a protective cover, fast-running, and watery pig). When pig eats different apples, you can replace them with corresponding sub-class instances (which is troublesome ). If there are four types of apples, you need to derive 4*3*2*1 = 24 subclasses for pig. If there are five types of apples ...... "How many child classes are there ".
If you use the decoration mode, you don't need to derive many sub-classes. When the pig eats an apple, we can add a new function to the pig dynamically in the decoration mode.
Structure:
Abstract Component (Component) Role: Provides an abstract interface to standardize the objects and abstract decorators preparing to receive additional responsibilities.
ConcreteComponent role: Defines a class to receive additional responsibilities.
Decorator role: An instance that holds a component object to describe it and define an interface consistent with the abstract Component Interface.
Concrete Decorator role: Adds "additional functions" to the component object.
Structure Code:
// Abstract component, which defines the implementation methods of specific components and abstract Decoration
Interface Component
{
Void operation ();
}
// Define specific components
Class concretecomponent: Component
{
Public void operation ()
{
Console. writeline ("concretecomponent operation ");
}
}
// Define the abstract modifier. The abstract decoration also implements the interface of the abstract component.
Abstract class Decorator: Component
{
// Use an abstract component as a member variable for abstract decoration.
Protected Component comp;
// Initialize the abstract component in the constructor.
Public Decorator (Component c)
{
This. comp = c;
}
// Method of the interface that has not been implemented.
Public abstract voidOperation();
}
// Specific modifier A, inherited from abstract decoration.
Class ConcreteDecoratorA: Decorator
{
Private stringAddedstate; // Member variables added to the specific Modifier
Public ConcreteDecoratorA (Component c): base (c ){}
Public stringAddedstate// Attributes added to the specific Modifier
{
Set
{
AddedState = value;
}
}
// The specific modifier implements the method defined in the interface
Public override void Operation ()
{
Comp. Operation ();// Call the Operation method of the original component object.
Console. WriteLine ("ConcreteDecoratorA Operation {0}", addedState );
}
}
// The specific modifier B inherits the self-Abstract decoration.
Class ConcreteDecoratorB: Decorator
{
Public ConcreteDecoratorB (Component c): base (c ){}
Public override void Operation ()
{
Comp. Operation ();// Call the Operation method of the original component object.
Console. WriteLine ("ConcreteDecoratorB Operation ");
}
// The specific modifier implements the method defined in the interface
Public voidAddedbehavior()
{
Console. WriteLine ("This is Added Behavior ");
}
}
Class Client
{
Public static void Main ()
{
// Native components
ConcreteComponent cc = new ConcreteComponent ();
Cc. Operation ();
// Use the specific native component as A package
ConcreteDecoratorA cda = new ConcreteDecoratorA (CC);
Cda. AddedState = "Decorator OK ";
Cda. Operation ();
// Use the specific native component to pack it once with the specific modifier B
ConcreteDecoratorB cdb = new ConcreteDecoratorB (CC);
Cdb. AddedBehavior ();
Cdb. Operation ();
// Re-package the specific component packaged by A with the specific modifier B.
ConcreteDecoratorB cdbcda = new ConcreteDecoratorB (CDA);
Cdbcda. Operation ();
}
}
Running result
Note:
The relationship between decorator and component is not only an inheritance relationship between a..., but also a composite relationship between has. You can use a concretedecorator to decorate a specific component object (concretecomponent). The decorated object is still of the component type.
The decorator mode solves the multi-direction extension of class functions, rather than the simple inheritance of classes.
The decorator mode provides more flexible function extensions than inheritance. By using different decorations to arrange and combine component objects, different functions can be combined.
DEMO code of the pig escape game:
// Abstract component, which is a common abstract interface of pig and decorator
Interface IUnit
{
Int Count {get;} // attribute to retrieve the number of existing pig records
Void move (); // method, pig running Method
Void attacked (); // method used to attack pig
}
// Specific component, Pig
Class Pig: Iunit
{
Private int pigCounts = 5; // a total of 5 Records
Public intCount
{
Get
{
Return pigCounts;
}
}
Public voidMove()
{
Console. WriteLine ("The Pig Is Moving ......");
}
Public voidAttacked()
{
Pigcounts --;// After the piglet is attacked, it loses its life.
Console. WriteLine ("The Pig Count Is: {0}", pigCounts); // display The number of Pig remaining
}
}
//Abstract decoration class,Abstract class used to decorate pig
Abstract classPigdecorator: iunit
{
Protected iunit pig;// Pig is a member variable of the decoration class.
Public PigDecorator (IUnit iu) // initialize the member variable in the constructor.
{
Pig = iu;
}
Public int Count
{
Get
{
Return pig. Count;
}
}
Public abstract void move ();
Public abstract void attacked ();
}
// Add a protective cover to the piglet
Class ProtectedPig: Pigdecorator
{
Public ProtectedPig (IUnit u)
: Base (u)
{
}
Public override void move ()
{
Pig. Move ();// Call the pig running method. Let pig run
}
Public override voidAttacked ()
{
// Rewrite the method by which the piglet is attacked.The lifecycle value is not reduced.. Shows the pig's life.
Console. WriteLine ("The Pig Count Is: {0}", pig. Count );
}
}
// Decorator that allows pig to run fast
Class FasterPig: PigDecorator
{
Public FasterPig (IUnit u)
: Base (u)
{
}
Public override void move ()
{
// Rewrite the pig running method to make it run faster.
Console. WriteLine ("The Pig Is Moving Faster Now ......");
}
Public override void attacked ()
{
Pig. attacked ();// When a piglet is attacked, the method of the piglet being attacked is called.
}
}
// Decorator that allows the pig to swim
Class swimpig: PigDecorator
{
Public swimpig (iunit U)
: Base (u)
{
}
Public override void move ()
{
Pig. Move (); // call the method of pig running.
}
Public override void attacked ()
{
Pig. Attacked (); // call the method of the piglet being attacked
}
// Add the swimming function to pig.
Public voidSwim ()
{
Console. writeline ("the pig can swim now ......");
}
}
// Red apple
Class redapple
{
Public protectedpig change (iunit U)
{
// Use a protective cover ornament to pack pig.
ProtectedPig p = new ProtectedPig (u );
Return P;
}
}
// Green apple
Class greenapple
{
Public fasterpig change (iunit U)
{
// Let the decorator to pack pig
FasterPig p = new FasterPig (u );
Return p;
}
}
// Yellow apple
Class YellowApple
{
// Pack pig with a swimming Ornament
Public SwimPig change (IUnit u)
{
SwimPig p = new SwimPig (u );
Return p;
}
}
// Grey Wolf
Class Monster
{
// Method of attacking pig
Public void attack (IUnit u)
{
U. attacked ();// Call the method of the piglet being attacked.
}
}
Class Client
{
Public static void Main (string [] args)
{
IUnit pig1 = new Pig (); // a native Pig
Monster M = new monster (); // a wolf
Pig1.move (); // start pig
// The wolf attacks the piglet and calls the method of the piglet being attacked. The Piglet's life is reduced by 1 and the remaining life is displayed.
M. Attack (pig1 );
Redapple r = new redapple (); // a red apple appears
Pig1 = R. Change (pig1); // pig eats the Red Apple, and the Red Apple uses the "protective cover" to decorate the pig as "protected pig"
Pig1.move ();
M. Attack (pig1); // at this time, when the wolf bit the pig again, it found that the pig had been decorated with a "protective cover" and did not reduce its vitality.
GreenApple g = new GreenApple (); // a green apple is displayed.
Pig1 = g. change (pig1); // pig with a "protective cover" Eats a green apple. At this time, pig has both a "protective cover" decoration and a "fast run" decoration.
Pig1.move (); // displays that pig is running fast
M. attack (pig1); // The piglet is under attack and its vitality remains intact.
YellowApple y = new YellowApple (); // a yellow apple appears
Pig1 = y. change (pig1); // Add the "swimming" package to the "fast-running" pig.
(SwimPig) pig1). move ();
(SwimPig) pig1). swim (); // pig swimming
M. attack (pig1); // the vitality of Piglets under attack remains intact
}
}
The Decorator mode uses Object combinations instead of inheritance to achieve dynamic extension of object functions at runtime, and can expand multiple functions as needed, this avoids the "poor flexibility" and "Multi-subclass Derivative Problems" caused by the independent use of inheritance ". At the same time, it is well in line with the "preferential use of object combination rather than inheritance" and "open-closed" principles in the object-oriented design principles. (