缘起,看到一遍文章,题材取自于《C++沉思录》,综合利用好几种设计模式,并且结合所谓的面向对象的技巧,然后洋洋自得,并且在最后,还反问:“有更好的解决方案吗?”。本座暗叹,又一个设计模式的毒害者。以下,就提出另一种解决方案。
首先,先声明一点,现实中,一张图片,可以给予添加一层又一层片框,也可以和其他的图片组合在一块,或横,或竖,……,但是,图片,始终只有一张,对它处理之后,它就一直是那个样子了,不可能同时看到它的两个样子,或加边框,或和其他照片组合在一块。如果,拿这张图片去进行复制,那又自是另当别论,但那已经是另外一第图片了。当然,对以下例子稍加修改,就能支持修饰的图片的复制操作。
本座最近在写一套消息框架,如果这个例子能用上那套框架,写起来就会很简单。但是,即使没有消息框架的支持,利用消息发送来解决这个问题,也是相当小儿科的事情。为了突出重点,忽略了各种异常处理,没有优化,也不管什么编程风格,纯粹直奔主题。解决这个例子的最重要一点,就在于打印图片时,要一行一行地从顶到底顺次打印下来。

typedef int (*ProcPictureImp)(void* pThis, int nMessage, void* param1, void* param2);


enum
{ PM_WIDTH, PM_HEIGHT, PM_PRINT_ROW};

struct PictureImp


{
void* pThis;
ProcPictureImp proc;

int GetWidth()

{
return (*proc)(pThis, PM_WIDTH, NULL, NULL);
}

int GetHeight()

{
return (*proc)(pThis, PM_HEIGHT, NULL, NULL);
}

int PrintRow(int nRow, ostream& out)

{
return (*proc)(pThis, PM_PRINT_ROW, (void*)nRow, (void*)&out);
}
};


class CPicture


{
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;
}
m_Imp.pThis = this;
m_Imp.proc = HandleMsg;
}
void Print(ostream& out);

public:
PictureImp m_Imp;

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_PRINT_ROW:
int nRow = (int)param1;
ostream& out = *(ostream*)param2;
if (nRow >= pSelf->m_nCount)
break;
int i=0;
for (; pSelf->m_pDatas[nRow][i] != 0; i++)
out << pSelf->m_pDatas[nRow][i];
for (; i<pSelf->m_nWidth; i++)
out << ' ';
}
return 0;
}

void CPicture::Print(ostream& out)


{
int nHeight = m_Imp.GetHeight();
for (int nRow = 0; nRow<nHeight; nRow++)

{
m_Imp.PrintRow(nRow, out);
out << endl;
}
}

class CFrameDecorater


{
public:
CFrameDecorater(PictureImp& imp)

{
m_PrevImp = imp;
imp.pThis = this;
imp.proc = HandleMsg;
}

private:
PictureImp 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;
PictureImp& prevImp = pSelf->m_PrevImp;
switch (nMessage)

{
case PM_WIDTH:
return prevImp.GetWidth()+2;

case PM_HEIGHT:
return prevImp.GetHeight()+2;

case PM_PRINT_ROW:
int nRow = (int)param1;
ostream& out = *(ostream*)param2;
bool bMyRow = nRow == 0 || nRow>prevImp.GetHeight();
if (nRow >= prevImp.GetWidth()+2)
break;
if (nRow == 0 || nRow>prevImp.GetHeight())

{
out << '+';
for (int i=0; i<prevImp.GetWidth(); i++)
out << '-';
out << '+';
}
else

{
out << '|';
prevImp.PrintRow(nRow-1, out);
out << '|';
}
}
return 0;
}


class CHorseDecorater


{
public:
CHorseDecorater(PictureImp& impLeft, PictureImp& impRight)

{
m_Left = impLeft;
m_Right = impRight;
impLeft.pThis = this;
impLeft.proc = HandleMsg;
impRight.pThis = this;
impRight.proc = HandleMsg;
}

private:
PictureImp m_Left;
PictureImp m_Right;

static int HandleMsg(void* pThis, int nMessage, void* param1, void* param2);
static void PrintRow(PictureImp& pict, int nRow, ostream& out)

{
if (nRow < pict.GetHeight())
pict.PrintRow(nRow, out);
else

{
for (int i=0; i<pict.GetWidth(); i++)
out << ' ';
}
}
};

int CHorseDecorater::HandleMsg(void* pThis, int nMessage, void* param1, void* param2)


{
CHorseDecorater* pSelf = (CHorseDecorater*)pThis;
PictureImp& pictLeft = pSelf->m_Left;
PictureImp& 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_PRINT_ROW:
int nRow = (int)param1;
ostream& out = *(ostream*)param2;
PrintRow(pictLeft, nRow, out);
PrintRow(pictRight, nRow, out);
}
return 0;
}

int main()


{

const char* init1[] =
{"Paris", "in the", "Spring", "HaHa"};
CPicture pict1(init1, 3);
pict1.Print(cout);
CFrameDecorater framer1(pict1.m_Imp);
//pict1.Print(cout);
CFrameDecorater framer2(pict1.m_Imp);
pict1.Print(cout);
CPicture pict2(init1, 4);
CHorseDecorater hors(pict1.m_Imp, pict2.m_Imp);
pict1.Print(cout);
CFrameDecorater framerHorse(pict1.m_Imp);
pict1.Print(cout);
return 0;
}
嗯,明眼人一眼就看出来了,切,这不过是模仿WINDOWS的窗口消息处理函数的伎俩而已。没有继承、没有虚函数,何其美妙哉!
又,注意到main()中的代码,虽然pict1被装饰了好几次,但其图片打印,始终都是pict1.Print(cout)。所谓不管八风乱起,我自岿然不动