Why, I saw an article (too lazy to hyperlink), re-studied the class exercise in "C ++ meditation", and made full use of several design modes, it is also very good to abide by the combined object-oriented principles. Well, in any case, it is really not easy to praise the skill of this student in object-oriented and design patterns. However, after crawling out of the mode stack, I had a big appetite for the mode. When I saw such a small exercise, I had to use such a multi-mode. Is this necessary? For me, every mode introduced in the Code indicates that various interfaces and virtual functions are to be added, and inheritance is necessary. I am very worried because, this means that the indirect layer is becoming increasingly thick and deviates from the nature of the problem.
Let's take a look at the description of this question in the meditation record. Well, I suggest you read the book on your own. The author provides two solutions to admire the writings of the author and the translator, the two solutions are well explained. Next, try another solution. First show the running effect of the Code.
For this class exercise, adding borders to the image is best suited to the decoration mode. However, the two images are not as easy as horizontal and vertical connections. However, first, you need to re-describe the problem. In reality, an image can be added with a layer after layer, or combined with other images, or vertical ,......, However, there is always only one image. After processing it, it will always look like that, and it cannot be seen at the same time. If you copy this image, it is another matter, but it is another new image.
The following design uses messages. If a ready-made message framework is supported, it will be easy to implement. However, even if the message framework is not supported, it is quite pediatric to solve this problem by sending messages. In order to highlight the key points, various exception handling is ignored, and no optimization is made. No matter what the programming style is, it simply goes straight to the topic. The most important thing to solve this problem is to print the image one by one from the top to the bottom. Therefore, first define the message that the image can send. It must process two messages, the image height (that is, the number of rows), and the data of each row of the image. That is
Enum {PM_HEIGHT, PM_ROW };
Struct PictureMsg
{
Typedef int (* ProcPictureMsg) (void * pThis, int nMessage, void * param1, void * param2 );
Public:
Void * pThis;
ProcPictureMsg proc;
Int GetHeight ()
{
Return (* proc) (pThis, PM_HEIGHT, NULL, NULL );
}
Int GetRow (int nRow, string & sRow)
{
Return (* proc) (pThis, PM_ROW, (void *) nRow, (void *) & sRow );
}
};
Ostream & operator <(ostream & out, PictureMsg & msg)
{
Int nHeight = msg. GetHeight ();
String sRow;
For (int nRow = 0; nRow <nHeight; nRow ++)
{
SRow. clear ();
Msg. GetRow (nRow, sRow );
Out <sRow;
Out <endl;
}
Return out;
} Www.2cto.com
The callback function is used to send messages. It would be better to make the callback function a member function, but since the c ++ member function is a big pitfall, I don't want to introduce functions or other delegate and other giants. In order to make it easier for customers to send messages, two auxiliary functions are specially compiled.
However, to send a message to an object, the object must be alive, that is, to create an object that can receive the message. Without the support of the message framework, and for ease of use, I had to write a specific class inherited from the image message structure and provided preliminary message processing, it is difficult to use inheritance.
Now, we can fully process the message. Requirements: the various decorative operations on images do not affect the original functions of the images, nor need to change the user's code. In other words, the image itself does not know that it has been processed by the outside world, and it still processes various messages as originally. Below, we only implement two kinds of decoration operations, adding borders and horizontal connections. As for vertical connections, it is very easy to implement. In addition, because the image width is required for decoration, a new message is added to the image message to process the image width.
Because it is a toy code, there is not much optimization in the next step, there are a few lines of code looks particularly ugly, especially the decoration method, forced to specify the picture on the left as the result of the operation, there are also the destructor of each decoration class, which can cancel the decoration of the image, and add new messages to return the copy of the image, or return the current decoration operation, or dynamic creation of decoration classes. In short, there are a variety of methods to optimize and upgrade without affecting the code structure. The following code is a little bit optimized from the first version.
Enum {PM_WIDTH, PM_HEIGHT, PM_ROW };
Struct PictureMsg
{
Typedef int (* ProcPictureMsg) (void * pThis, int nMessage, void * param1, void * param2 );
Public:
Void * pThis;
ProcPictureMsg proc;
Int GetWidth ()
{
Return (* proc) (pThis, PM_WIDTH, NULL, NULL );
}
Int GetHeight ()
{
Return (* proc) (pThis, PM_HEIGHT, NULL, NULL );
}
Int GetRow (int nRow, string & sRow)
{
Return (* proc) (pThis, PM_ROW, (void *) nRow, (void *) & sRow );
}
};
Ostream & operator <(ostream & out, PictureMsg & msg)
{
Int nHeight = msg. GetHeight ();
String sRow;
For (int nRow = 0; nRow <nHeight; nRow ++)
{
SRow. clear ();
Msg. GetRow (nRow, sRow );
Out <sRow;
Out <endl;
}
Return out;
}
Class CPicture: public PictureMsg
{
Public:
CPicture (const char * pDatas [], int nCount)
{
M_pDatas = pDatas;
M_nCount = nCount;
M_nWidth = 0;
For (int I = 0; I <m_nCount; I ++)
{
Int nLen = strlen (m_pDatas [I]);
If (m_nWidth <nLen)
M_nWidth = nLen;
}
PThis = this;
Proc = HandleMsg;
}
Private:
Const char *** m_pDatas;
Int m_nCount;
Int m_nWidth;
Static int HandleMsg (void * pThis, int nMessage, void * param1, void * param2 );
};
Int CPicture: HandleMsg (void * pThis, int nMessage, void * param1, void * param2)
{
CPicture * pSelf = (CPicture *) pThis;
Switch (nMessage)
{
Case PM_WIDTH:
Return pSelf-> m_nWidth;
Case PM_HEIGHT:
Return pSelf-> m_nCount;
Break;
Case PM_ROW:
Int nRow = (int) param1;
String & sRow = * (string *) param2;
If (nRow> = pSelf-> m_nCount)
Break;
Int I = 0;
For (; pSelf-> m_pDatas [nRow] [I]! = 0; I ++)
SRow. push_back (pSelf-> m_pDatas [nRow] [I]);
For (; I <pSelf-> m_nWidth; I ++)
SRow. push_back ('');
}
Return 0;
}
Class CFrameDecorater
{
Public:
CFrameDecorater (PictureMsg & imp)
{
M_PrevImp = imp;
Imp. pThis = this;
Imp. proc = HandleMsg;
}
Private:
PictureMsg m_PrevImp;
Static int HandleMsg (void * pThis, int nMessage, void * param1, void * param2 );
};
Int CFrameDecorater: HandleMsg (void * pThis, int nMessage, void * param1, void * param2)
{
CFrameDecorater * pSelf = (CFrameDecorater *) pThis;
PictureMsg & prevImp = pSelf-> m_PrevImp;
Switch (nMessage)
{
Case PM_WIDTH:
Return prevImp. GetWidth () + 2;
Case PM_HEIGHT:
Return prevImp. GetHeight () + 2;
Case PM_ROW:
Int nRow = (int) param1;
String & sRow = * (string *) param2;
Bool bMyRow = nRow = 0 | nRow> prevImp. GetHeight ();
If (nRow> = prevImp. GetWidth () + 2)
Break;
If (nRow = 0 | nRow> prevImp. GetHeight ())
{
SRow. push_back ('+ ');
For (int I = 0; I <prevImp. GetWidth (); I ++)
SRow. push_back ('-');
SRow. push_back ('+ ');
}
Else
{
SRow. push_back ('| ');
PrevImp. GetRow (nRow-1, sRow );
SRow. push_back ('| ');
}
}
Return 0;
}
Class CHorseDecorater
{
Public:
CHorseDecorater (PictureMsg & impLeft, PictureMsg & impRight)
{
M_Left = impLeft;
M_Right = impRight;
ImpLeft. pThis = this;
ImpLeft. proc = HandleMsg;
}
Private:
PictureMsg m_Left;
PictureMsg m_Right;
Static int HandleMsg (void * pThis, int nMessage, void * param1, void * param2 );
Static void PrintRow (PictureMsg & pict, int nRow, string & sRow)
{
If (nRow <pict. GetHeight ())
Pict. GetRow (nRow, sRow );
Else
{
For (int I = 0; I <pict. GetWidth (); I ++)
SRow. push_back ('');
}
}
};
Int CHorseDecorater: HandleMsg (void * pThis, int nMessage, void * param1, void * param2)
{
CHorseDecorater * pSelf = (CHorseDecorater *) pThis;
PictureMsg & pictLeft = pSelf-> m_Left;
PictureMsg & pictRight = pSelf-> m_Right;
Switch (nMessage)
{
Case PM_WIDTH:
Return pictLeft. GetWidth () + pictRight. GetWidth ();;
Case PM_HEIGHT:
Return max (pictLeft. GetHeight (), pictRight. GetHeight ());
Case PM_ROW:
Int nRow = (int) param1;
String & sRow = * (string *) param2;
PrintRow (pictLeft, nRow, sRow );
PrintRow (pictRight, nRow, sRow );
}
Return 0;
}
Int main ()
{
Const char * init1 [] = {"Paris", "in the", "Spring", "HaHa "};
CPicture pict1 (init1, 3 );
// Cout <pict1;
CFrameDecorater framer1 (pict1 );
// Cout <pict1;
CFrameDecorater framer2 (pict1 );
// Cout <pict1;
CPicture pict2 (init1, 4 );
CHorseDecorater hors (pict1, pict2 );
// Cout <pict1;
CFrameDecorater framerHorse (pict1 );
// Cout <pict1;
CHorseDecorater hors2 (pict2, pict1 );
// Cout <pict2;
CFrameDecorater framer3 (pict2 );
CHorseDecorater hors3 (pict1, pict2 );
Cout <pict1;
Return 0;
}
Author huaxiazhihuo