C + + design mode 6 (Decorator decorative mode)

Source: Internet
Author: User

4. The "single-duty" class model

In the design of software components, if the division of responsibility is not clear, the use of inheritance results often with the change in demand, the subclass of the rapid expansion, and full of repetitive code, the key is to draw responsibility.

Typical mode representative: Decorator,bridge

4.1 Decorator Decoration Mode

code Examples : different flow operations (file streams, network streams, memory streams) and their extended functions (encryption, buffering) and other implementations

Implementation Code 1:

Class diagram structure schematic (heavy use inheritance)

Data size: Suppose there are n kinds of files, m function operation. The implementation method has (1 + n + N * m! /2) Sub-class of order of magnitude;

At the same time, 59 rows, 79 rows, 98 rows are the same code (similar to many), there is a lot of redundancy and repetition.

Start refactoring, see Method 2.

  1//decorator1.cpp 2//Business Operation 3 class stream{4 public:5 virtual char Read (int number) = 0;  6 virtual void Seek (int position) = 0;  7 virtual void Write (char data) = 0; 8 9 Virtual ~stream () {} 10};     11 12//Body class Filestream:public stream{public:15 virtual char read (int number) {16//Read file stream 17 } (virtual void Seek (int position) {19//location file stream) + virtual void Write (char data) {22// Write file stream 23} 24 25};     Class NetworkStream:p ublic stream{public:29 virtual char read (int number) {30//Read network stream 31} 32 virtual void Seek (int position) {33//Location network stream) + virtual void write (char data) {36//write Network stream 3 7} 38 39};     MemoryStream class:p ublic stream{public:43 virtual char read (int number) {44//Read memory stream 45} 46 virtual void Seek (int position) {47//Location memory stream-$}-virtual void write (char data) {50//write Memory Stream 51     } 52 53};          54 55//Extended Operation Cryptofilestream class:p ublic filestream{public:58 virtual char Read (int number) {59 60 Extra encryption Operation ... Filestream::read (number);//Read file stream (*//) + virtual void Seek (int position) {65//Extra encryption Operation... Filestream::seek (position);//Location file stream 67//extra encryption operation ... "(Byte data) {70//extra encryption operation ...) Filestream::write (data);//write file stream 72//extra encryption operation ... 73} 74};         Cryptonetworkstream class::p ublic networkstream{public:78 virtual char Read (int number) {79 80 Extra encryption Operation ... Bayi Networkstream::read (number);//Read Network stream-------------"(int position) {84//extra encryption operation ... Networkstream::seek (position)///Location Network stream 86//additional encryption operation ... * * * * virtual void Write (Byte data) {89//extra encryption operation ... Networkstream::write (data)//write network stream 91//Extra encryption operation ... 92} 93};         94 Cryptomemorystream:public memorystream{public:97 Virtual char Read (int number) {98 99 Extra encryption Operation ... Memorystream::read (number);//Read Memory Stream 101}102 virtual void Seek (int position) {103//extra encryption operation ... 104 Memorystream::seek (position);//Location Memory stream 105//extra encryption operation ... 106}107 virtual void Write (Byte data) {108//extra encryption operation ... 109 Memorystream::write (data);//write Memory stream 110//extra encryption operation ... 111}112};113 class Bufferedfilestream:public filestream{115/... };117 118 class Bufferednetworkstream:public networkstream{119//... };121 122 class Bufferedmemorystream:public memorystream{123//... 124}125 126 127 129 class Cryptobufferedfilestream:p ublic filestream{130 public:131 virtual char Read (int number {132 133//Extra encryption operation ... 134//Extra buffering operation ... 135 filestream::read (number);//Read file stream 136}137 virtual void Seek (int position) {138//extraThe encryption operation ... 139//Extra buffering operation ... Filestream::seek (position);//location File stream 141//extra encryption operation ... 142//Extra buffering operation ... 143}144 virtual void Write (Byte data) {145//extra encryption operation ... 146//Extra buffering operation ... 147 Filestream::write (data);//write file stream 148//extra encryption operation ... 149//Extra buffering operation ... }151};152 153 154 155 void Process () {156 157//compile-time assembly 158 cryptofilestream *FS1 = new Cryptofilestream ( ); 159 Bufferedfilestream *FS2 = new Bufferedfilestream (); 161 162 Cryptobufferedfilestream *FS3 =new CryptoBuff Eredfilestream (); 163 164}

Implementation Code 2:

For the above code, the refactoring steps are as follows:

1) Examine the Cryptofilestream, cryptonetworkstream,cryptomemorystream three classes, and change their inheritance filestream,networkstream,networkstream to a combination ; that is

1 class cryptofilestream{2     filestream* stream; 3 public:4     virtual char Read (int number) {5         6         //extra cryptographic operation. .. 7         Stream, read (number),//Call Read () 8         //... seek () write () Similarly 9     }10} one    class Cryptonetworks tream{13     networkstream* stream;14 public:15     virtual char Read (int number) {+         //Extra encryption operation ... Read (number         ),//Use the field mode to invoke read ()         //... seek () write () Same as     }21}    cryptomemorystream{24     memorystream* stream;25 public:26     virtual char Read (int number) {+         // Extra encryption Operation ... Read (number         ), or//Use the field to call Read ()         //... seek () write ()     }32}    

2) Investigate the above 2 rows, 13 rows, 24 rows, found that it is the stream subclass, should use polymorphism to continue to reconstruct.

1 class cryptofilestream{2     stream* Stream;//= new FileStream () 3 public:4     virtual char Read (int number) {5
   
    6         //Extra encryption operation ... 7         Stream, read (number),//Call Read () 8         //... seek () write () Similarly 9     }10} one    class Cryptonetworks tream{13     stream* Stream;//= new NetworkStream (); public:15     virtual char Read (int number) {+/         / Extra encryption Operation ... Read (number         ),//Use the field mode to invoke read ()         //... seek () write () Same as     }21}    cryptomemorystream{24     stream* Stream;//= Newmemorystream () public:26     virtual char Read (int number) {27         //Extra encryption operation ... Read (number         ), or//Use the field to call Read ()         //... seek () write ()     }32}    
   

3) found that three classes are the same, different implementations (requirements change) are implemented at runtime, compile-time reuse, change to a class, named CryptoStream.

At the same time, in order to ensure that the interface specification (Read,seek and so on is still a virtual function), inherit stream, there are both combinations, and inheritance situation.

1 class cryptostream:public stream{2     stream* Stream;//= new ... 3 public:4     Virtual char Read (int number) {5         6         //Extra encryption operation ... 7         Stream, read (number);//Call Read () 8         //... seek () write () Similarly 9     }10}   

4) Add the corresponding constructor, get the results of this round reconstruction, the code is as follows, the main view of the use (runtime assembly):

  1//decorator2.cpp 2 class stream{3 4 public:5 virtual char Read (int number) = 0;  6 virtual void Seek (int position) = 0;  7 virtual void Write (char data) = 0; 8 9 Virtual ~stream () {} 10};     11 12//Body class Filestream:public stream{public:15 virtual char read (int number) {16//Read file stream 17 } (virtual void Seek (int position) {19//location file stream) + virtual void Write (char data) {22// Write file stream 23} 24 25};     Class NetworkStream:p ublic stream{public:29 virtual char read (int number) {30//Read network stream 31} 32 virtual void Seek (int position) {33//Location network stream) + virtual void write (char data) {36//write Network stream 3 7} 38 39};     MemoryStream class:p ublic stream{public:43 virtual char read (int number) {44//Read memory stream 45} 46      virtual void Seek (int position) {47//Location memory stream-$}-virtual void write (char data) {50//write Memory Stream 51 } 52 53}; 54 55//Extended operation Cryptostream:public Stream {stream* stream;//...  public:63 CryptoStream (stream* stm): Stream (STM) {+ +} Number) {69 70//Extra encryption operation ... Stream->read (number);//Read file stream position} The virtual void Seek (int) {74//extra encryption operation ... Stream::seek (position);//location File stream 76//extra encryption operation ... * * + virtual void Write (Byte data) {79//extra encryption operation ... Stream::write (data)//write file stream 81//extra encryption operation ... 82} 83}; The Bufferedstream:public stream{, stream* stream;//... public:92 BufferedStream (stream* stm): Stream (STM) {93 94} 95//... 96}; 98 101 102 void Process () {103 104//runtime assembly filestream* s1=new FileStream (); 106 cryptostream* s2= New CryptoStream (S1); 107 108 bufferedstream* S3=new BufferedStream(s1); 109 bufferedstream* s4=new BufferedStream (S2); 111 112 113 114} 

Implementation Code 3:

The above implementation code 2 has greatly relieved the redundancy problem, conforms to the object-oriented design idea, the wheel reconstruction is icing on the cake.

The refactoring steps are as follows:

Examining the code above, many subclasses have the same field (stream* stream;//... )

There are two ways to consider "up-and-down", the first of which is to refer to the base class (which is obviously inappropriate, FileStream etc. does not require the stream field)

So consider the second approach and implement a "middle class".

Decoratorstream:public stream{protected:    stream* stream;//        ... Decoratorstream (Stream * stm): Stream (STM) {        }    };

CryptoStream such as inheriting intermediate class Decoratorstream:

Class Cryptostream:public Decoratorstream {public:    CryptoStream (stream* stm):D Ecoratorstream (STM) {        }    / /...}    

The final version of the refactoring completed:

Filestream,networkstream,memorystream and so on can create their own objects;

However, to implement encryption, the caching function must be based on existing filestream/networkstream and other objects;

These operations are essentially extended operations, meaning "decorations".

At this point the class diagram illustrates:

At this point the number of classes is (1 + n + 1 + m)

  1//decorator3.cpp 2 class stream{3 4 public:5 virtual char Read (int number) = 0;  6 virtual void Seek (int position) = 0;  7 virtual void Write (char data) = 0; 8 9 Virtual ~stream () {} 10};     11 12//Body class Filestream:public stream{public:15 virtual char read (int number) {16//Read file stream 17 } (virtual void Seek (int position) {19//location file stream) + virtual void Write (char data) {22// Write file stream 23} 24 25};     Class NetworkStream:p ublic stream{public:29 virtual char read (int number) {30//Read network stream 31} 32 virtual void Seek (int position) {33//Location network stream) + virtual void write (char data) {36//write Network stream 3 7} 38 39};     MemoryStream class:p ublic stream{public:43 virtual char read (int number) {44//Read memory stream 45} 46      virtual void Seek (int position) {47//Location memory stream-$}-virtual void write (char data) {50//write Memory Stream 51 } 52 53}; 54 55//Extended Operation Decoratorstream:public stream{protected:59 stream* stream;//... Decoratorstream (Stream * stm): Stream (STM) {62 63} 64 65}; Cryptostream:public Decoratorstream {public:71 CryptoStream (stream* stm):D Ecoratorstream (s TM) {77 78//Extra encryption operation ...) {"* * *}" Stream->read (number);//Read file stream----} Bayi virtual void Seek (int position) {82//extra encryption operation ... Stream::seek (position);//Location File stream 84//additional encryption operation ... $87//Extra encryption operation ... for the virtual void Write (Byte data) Stream::write (data);//write file stream 89//extra encryption operation ... 90} 91}; 94 Bufferedstream:public decoratorstream{-stream* stream;//... 98 public:100 BufferedStream (stream* stm):D Ecoratorstream (STM) {101 102}103/... 104};105 106 107 108 109 void PRocess () {110 111//runtime assembly of the filestream* S1=new FileStream (); 113-cryptostream* s2=new CryptoStream (S1);     bufferedstream* s3=new BufferedStream (S1); 117 118 bufferedstream* S4=new BufferedStream (S2); 119 120 121 122}

Decorator Mode Use motive:

In some cases we may "use inheritance to extend the functionality of an object", because the underlying type introduces static specific, which makes this extension inflexible, and as the number of subclasses increases (the expansion function increases), the composition of each subclass (the combination of extended functions) causes the expansion of various subclasses.

Schema Definition:

Add some additional accusations to an object dynamically (in combination). For added functionality, the decorator mode is more flexible than the acoustic Class (inheritance) (eliminating duplicate code & reducing the number of subclasses)

Class Diagram:

Summary of key points:

1. By adopting a combination that is not inherited, the decorator pattern enables the ability to dynamically extend the functionality of the object at run time, and can extend multiple functions as needed. Avoids the "poor flexibility" and "multi-subclass derivation issues" that are associated with inheritance

The 2.Decorator class behaves as an inheritance of is-a component on the interface, that is, the decorator class inherits the interfaces that the component class has. But in the implementation of the HAS-A component of the composition of the relationship, that is, decorator class and use another component class.

The purpose of 3.Decorator mode is not to solve the "multi-Inheritance" problem of "multi-word derivation", the main point of Decorator mode application is to solve "the expansion function of principal class in multiple directions" (obviously file,network and encryption, buffer is two kinds of extension direction)--is the meaning of "adornment".

Reference documents:

Li Jianzhong Teacher "C + + design mode" online course

Design pattern: The basis of reusable object-oriented software

C + + design mode 6 (Decorator decorative mode)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.