“This is the seventh day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”

An introduction to the decorator pattern

The core of a decorator is to add functionality to a class without changing the original class. You can avoid too many subclasses from inheritance, and you can avoid the complexity of AOP.

Decorators mainly solve the problem of subclass expansion due to the continuous horizontal expansion of functions under direct inheritance. Instead, the decorator pattern is more flexible than direct inheritance and also eliminates the need to consider the maintenance of subclasses.

In the process of implementation, the specific implementation only cares about the function of the extension, while the core services of the original class will not be affected, and there will not be redundant subclasses caused by the use of inheritance, which increases the overall flexibility.

The decorator pattern satisfies the single responsibility principle by extending functional logic in its own decorator class without affecting the main class, while adding and removing that logic at runtime as needed. In addition, the decorator pattern and the inherited superclass override method need to be selected on demand at some time, not necessarily one is the best.

The emphasis of the decorator implementation is on the use of the methods of the interface inherited by the abstract class, and on the setting that the inherited interface can pass its implementation class through the constructor, thereby increasing the extensibility and overwriting the methods that can implement this part of the superclass.

A wrapper is an object that can connect to other target objects. The wrapper contains the same set of methods as the target object, and it delegates all received requests to the target object, but the wrapper can process the request before and after it is delegated to the target, which may change the final result.

Because the target object and decorator follow the same interface, you can encapsulate an object with decorators an infinite number of times. The resulting object will acquire the behavior of all the wrappers combined.

Abstract point of the decorator pattern

  • Abstract Component role – Defines abstract interfaces

  • Concrete component role – implements abstract interfaces, which can be a group

  • Decorator role – Defines abstract classes and inherits methods from the interface, ensuring consistency

  • Concrete decorator role – Extends the implementation logic of the concrete decorator


Several serious issues that can arise from succession:

1. Inheritance is static. You cannot change the behavior of an existing object at run time. You can only replace the entire object with objects created by different subclasses.

2. A subclass can only have one parent. Most programming languages do not support multiple inheritance.

Decorator construction

  • A part declares a common interface to the wrapper and the encapsulated object.
  • The concrete component class is the class to which the encapsulated object belongs. It defines the underlying behavior, but the decorator class can change those behaviors.
  • The base decorator class has a reference member variable that points to the encapsulated object. The type of the variable should be declared as a generic widget interface so that it can refer to specific widgets and decorations. Decorating the base class delegates all operations to the encapsulated object.
  • The concrete decorator class defines additional behavior that can be added dynamically to a part. The concrete decorator class overrides the method that decorates the base class and performs additional behavior before or after calling the superclass method.
  • A client can use multiple layers of decoration to encapsulate a part, as long as it interacts with all objects using a common interface.

Applicable scenario

When you can use an object without modifying the code and want to add additional behavior to the object at run time, you can use the decorator mode.

Decorators organize business logic into a hierarchy. You can create a decorator for each layer, and at runtime compose the various pieces of logic into objects. Since these objects all follow a common interface, client code can use them in the same way.

2, when some business cannot use inheritance to extend object behavior, can use decoration pattern.

The decorator pattern has advantages and disadvantages

Advantages:

  • You need to create new subclasses to extend the behavior of the object.

  • The ability to add or remove objects at run time.

  • You can combine several behaviors with multiple decorator wrapper objects.

  • Meet the single responsibility principle.

Disadvantages:

  • Removing a specific wrapper from the wrapper stack is difficult

  • It is difficult to implement decorations whose behavior is not affected by the order of the decorator stack

  • The initial configuration code for each layer is poor at first

Demo

/// <summary> public abstract class Component {public abstract string Operation(); }}Copy the code
/ / / < summary > / / / / / / abstract a decorator < summary > class ConcreteComponent: Component {public override string Operation () {return "ConcreteComponent"; }}Copy the code
abstract class Decorator:Component { protected Component _component; public Decorator(Component component) { this._component = component; } public void SetComponent(Component component) { this._component = component; } public override string Operation() { if (this._component! =null) { return this._component.Operation(); } else { return string.Empty; }}}Copy the code
class ConcreteDecoratorA : Decorator { public ConcreteDecoratorA(Component comp):base(comp) { } public override string Operation() { return "ConcreteDecoratorA " + base.Operation(); } } class ConcreteDecoratorB:Decorator { public ConcreteDecoratorB(Component comp) : base(comp) { } public override string Operation() { return "ConcreteDecoratorA " + base.Operation(); }}Copy the code
Public class Client {public void ClientCode(Component Component) {console. WriteLine("Result: "+ component.operation ()); }}Copy the code
class Program { static void Main(string[] args) { Client client = new Client(); var temp = new ConcreteComponent(); Console.WriteLine("Start------"); Console.WriteLine(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(temp); ConcreteDecoratorB d2 = new ConcreteDecoratorB(d1); Console.WriteLine("Start Music"); client.ClientCode(d2); Console.ReadKey(); }}Copy the code

In fact, we can see that the decorator pattern is similar to the composition pattern. The decorator pattern is a rewritable method of an existing class, that is, you can change the structure of its methods, while the composition pattern cannot change the methods of an existing class, only to combine them into the desired implementation.

Small remarks

Life is short, I don’t want to pursue what I can’t see, I just want to grasp what I can see.

I am A hui, thank you for reading, if it is helpful to you, please click like, forward thank you.