C # decorator mode in Design Mode,
In software development, we often want to add different features to a class of objects, such as adding film, cell phone pendants, and cell phone casings to the mobile phone. If inheritance is used for implementation at this time, numerous classes need to be defined, such as StickerPhone (mobile phone film) and AccessoriesPhone (pendant mobile phone class), which will lead to the "subclass explosion" problem. To solve this problem, we can use the modifier mode to dynamically add additional responsibilities to an object. Next let's take a look at the modifier mode.
1. Decorator Mode
The modifier mode dynamically attaches more responsibilities to an object in a way that is transparent to the customer. The modifier mode provides more flexibility to add features than the subclass generation.
Ii. Class diagram of the modifier Mode
In the modifier mode, the roles are:
Abstract component (Phone) Role: provides an abstract interface to standardize the objects to accept additional responsibilities.
AppPhone role: defines a class that will receive additional responsibilities.
Dicorator: holds an instance of a Component object and defines an interface consistent with the abstract Component Interface.
The specific Decoration (Sticker and Accessories) role is responsible for attaching "additional responsibilities" to the component object.
Iii. Implementation of the decorator Model
Here, the example of mobile phone and mobile phone accessories is used to demonstrate the implementation of the decorator mode. The specific code is as follows:
using System;///
/// Mobile phone abstract class, that is, the abstract component class in the modifier mode ///
public abstract class Phone{ public abstract void Print();}///
/// The Apple mobile phone, that is, the specific component class in the decorative mode ///
public class ApplePhone : Phone{ ///
/// Override the base class method ///
Public override void Print () {Console. WriteLine ("start to execute the specific object-Apple mobile phone ");}}///
/// Abstract decoration class. to completely replace abstract components with decoration, the decoration must inherit from Photo ///
public abstract class Decorator : Phone{ private readonly Phone _phone; protected Decorator(Phone p) { this._phone = p; } public override void Print() { if (_phone != null) { _phone.Print(); } }}///
/// Film, that is, the specific modifier ///
Public class Sticker: Decorator {public Sticker (Phone p): base (p) {}public override void Print () {base. print (); // Add a new behavior AddSticker ();}///
/// New behavior method ///
Public void AddSticker () {Console. WriteLine ("Apple mobile phone now has a film ");}}///
/// Cell phone pendant ///
Public class Accessories: Decorator {public Accessories (Phone p): base (p) {}public override void Print () {base. print (); // Add a new behavior AddAccessories ();}///
/// New behavior method ///
Public void AddAccessories () {Console. WriteLine ("Now the iPhone has a pretty pendant ");}}
The client call code is as follows:
Using System; class Customer {static void Main (string [] args) {// I bought an apple Phone, phone = new ApplePhone (); // now I want to film Decorator applePhoneWithSticker = new Sticker (phone); // expand the film behavior applePhoneWithSticker. print (); Console. writeLine ("---------------------- \ n"); // now I want to have the Decorator applePhoneWithAccessories = new Accessories (phone); // extend the mobile phone pendant behavior applePhoneWithAccessories. print (); Console. writeLine ("-------------------- \ n"); // now I have Sticker sticker = new Sticker (phone); Accessories identifier = new Accessories (sticker); identifier. print (); Console. readLine ();}}
From the client code above, the client can dynamically Add the mobile phone accessories to the mobile phone. To add the mobile phone shell, you only need to add a mobile phone shell class that inherits the Decorator, the modifier mode is also highly scalable.
Iv. Use Cases
Next let's take a look at the specific circumstances in which the decorator mode is used. In the following cases, the decorator mode should be used:
You need to expand the functions of a class or add additional responsibilities to a class.
You need to dynamically add functions to an object. These functions can be dynamically revoked.
A large number of functions are generated by the arrangement and combination of some basic functions.
V. Implementation of the modifier mode in. NET
In the. NET class library, there is also the implementation of the modifier mode, which is System. IO. Stream. Let's look at the Stream class structure:
In, BufferedStream, CryptoStream, and GZipStream are actually two specific decoration classes. Here, the Decorator mode ignores the abstract decoration role (Decorator ). The following shows how the client dynamically adds features to MemoryStream.
MemoryStream memoryStream = new MemoryStream (new byte [] {, 98, 99}); // extended buffer function BufferedStream buffStream = new BufferedStream (memoryStream ); // Add encryption function CryptoStream cryptoStream = new CryptoStream (memoryStream, new AesManaged (). createEncryptor (), CryptoStreamMode. write); // Add the compression function GZipStream gzipStream = new GZipStream (memoryStream, CompressionMode. compress, true );
Vi. Advantages and disadvantages of the decorator Model
Advantages:
Both the decoration mode and the inheritance mode aim to expand the object functions, but the decoration mode is more flexible than the inheritance mode.
By using different decorative classes and the arrangement and combination of these classes, designers can create a combination of many different behaviors.
The modifier mode has good scalability.
Disadvantages:
The decorator pattern can lead to many small objects in the design. Excessive use of it will make the program more complex. In addition, more objects may become difficult to make mistakes, especially those objects.
VII. Summary
Now, the introduction of the decorator mode is over. The decorator mode uses Object combination instead of inheritance to dynamically expand the object function during re-running, in addition, you can expand multiple functions as needed to avoid the "flexibility difference" and "Multi-subclass Derivative Problems" caused by the independent use of inheritance. At the same time, it is well in line with the object-oriented design principles of "preferential use of object combinations rather than inheritance" and "open-closed.