Decorate(修饰模式)

前言:
当希望动态地为一个对象(有时候我们想给某个对象添加一些职责, 而不是整个类)填写一些额外的职责时, 修饰模式比生成子类更加的灵活

示例:
以一个CTextView为例, 我们现在有一个文本视图类, 该类提供一个基本的文本编辑框, 当我们渴望拥有一个带滚动条的文本视图时, 我们也许会从CTextView类中派生出一个CScrollTextVIew, 而当我们想要一个带边框的文本视图时, 我们也许会派生出一个CBorderTextView, 可是如果我们想要一个既带滚动条, 又拥有边框的文本视图呢? CScrollBorderTextView? 也可以, 但这并不灵活

如果现在需求发生变动, 我想要有一个边框, 当文本过多时, 它有垂直滚动条, 当文本过长时, 它有水平滚动条, 当客户希望时, 它又可以有阴影等效果, 如果继续使用继承的方式来满足需求, 我想应当是非常痛苦的

修饰模式可以满足我们的需求, 它使我们可以为一个对象添加一些额外的职责, 而这些额外的职责对于对象本身而言是透明的

代码:

// 抽象视图类
class CView
{
// 函数定义
public:
    // 构造函数
    CView(void) {}
    // 析构函数
    ~CView(void) {}

// 外部接口
public:
    // 绘制函数
    virtual void Draw(void) {}
};

// 抽象装饰类
class CDecorate:public CView
{
// 变量定义
private:
    CView* m_pView;

// 函数定义
public:
    // 构造函数
    CDecorate(CView* view) { m_pView = view; }
    // 析构函数
    ~CDecorate(void) {}

// 外部接口
public:
    // 绘制函数
    virtual void Draw(void) { m_pView->Draw(); }
};

// 滚动条装饰类
class CScrollBars:public CDecorate
{
// 函数定义
public:
    // 构造函数
    CScrollBars(CView* view) : CDecorate(view){}
    // 析构函数
    ~CScrollBars(void) {}

// 内部函数
protected:
    // 绘制滚动条
    void DrawScrollBars(void)
    {
        printf("> 绘制一个滚动条\r\n");
    }

// 外部接口
public:
    // 绘制函数
    virtual void Draw(void)
    {
        CDecorate::Draw();
        DrawScrollBars();
    }
};

// 边框装饰类
class CBorder:public CDecorate
{
// 函数定义
public:
    // 构造函数
    CBorder(CView* view) : CDecorate(view){}
    // 析构函数
    ~CBorder(void) {}

// 内部函数
protected:
    // 绘制边框
    void DrawBorder(void)
    {
        printf("> 绘制一个边框\r\n");
    }

// 外部接口
public:
    // 绘制函数
    virtual void Draw(void)
    {
        CDecorate::Draw();
        DrawBorder();
    }
};

// 文本视图类
class CTextView:public CView
{
// 变量定义
protected:
    char m_Text[MAX_PATH];

// 函数定义
public:
    // 构造函数
    CTextView(char* s) { SetWindowText(s); }
    // 析构函数
    ~CTextView(void) {}

// 内部函数
protected:
    // 绘制文本视图
    virtual void DrawTextView(void)
    {
        printf("> 绘制一个文本视图, 文本内容为:%s\r\n", m_Text);
    }

// 外部接口
public:
    // 绘制函数
    virtual void Draw(void)
    {
        CView::Draw();
        DrawTextView();
    }

    // 设置窗口文本
    void SetWindowText(char* s)
    {
        strcpy_s(m_Text, _countof(m_Text), s);
    }

    // 获取窗口文本
    char* GetWindowText(void)
    {
        return m_Text;
    }
};

// 窗口类
class CWindows
{
// 变量定义
protected:
    CView* m_arrWindow[10];

// 函数定义
public:
    // 构造函数
    CWindows(void) { ZeroMemory(m_arrWindow, sizeof(CView*) * 10); }
    // 析构函数
    ~CWindows(void) { ZeroMemory(m_arrWindow, sizeof(CView*) * 10); }

// 外部接口
public:
    // 绘制窗口
    void Draw(void)
    {
        for (int nI=0; nI<10; nI++)
        {
            if (m_arrWindow[nI] != NULL)    m_arrWindow[nI]->Draw();
        }
    }

    // 添加控件
    void AddControl(CView* pView)
    {
        for (int nI=0; nI<10; nI++)
        {
            if (m_arrWindow[nI] == NULL)    { m_arrWindow[nI] = pView; break; }
        }
    }

    // 移除控件
    void RemoveControl(CView* pView)
    {
        for (int nI=0; nI<10; nI++)
        {
            if (m_arrWindow[nI] == pView)   { m_arrWindow[nI] = NULL; break; }
        }
    }
};

int _tmain(int argc, _TCHAR* argv[])
{
    // 定义一个窗口对象
    CWindows WindowsObject;

    // 定义一个普通的文本视图
    CTextView TextView("我是一个文本视图控件");

    // 将文本视图作为一个控件添加进窗口对象中
    WindowsObject.AddControl(&TextView);

    // 使窗口对象绘制自身
    WindowsObject.Draw();
    printf("----------------------------------------\r\n");

    // 将文本视图从窗口对象中移除
    WindowsObject.RemoveControl(&TextView);
//---------------------------//
    // 现在给这个文本视图加上一个滚动条
    CScrollBars* pScrollBars = new CScrollBars(&TextView);

    // 添加"带滚动条的文本视图"到窗口对象中
    WindowsObject.AddControl(pScrollBars);

    // 使窗口对象绘制自身
    WindowsObject.Draw();
    printf("----------------------------------------\r\n");

    // 将"带滚动条的文本视图"从窗口对象中移除
    WindowsObject.RemoveControl(pScrollBars);
    delete pScrollBars;
//---------------------------//
    // 现在给这个文本视图加上一个边框
    CBorder* pBorderObject = new CBorder(&TextView);

    // 添加"带边框的文本视图"到窗口对象中
    WindowsObject.AddControl(pBorderObject);

    // 使窗口对象绘制自身
    WindowsObject.Draw();
    printf("----------------------------------------\r\n");

    // 将"带边框的文本视图"从窗口对象中移除
    WindowsObject.RemoveControl(pBorderObject);
    delete pBorderObject;
//---------------------------//
    // 现在给这个文本视图加上一个边框, 又加上一个滚动条
    CBorder* pBorderScrollBars = new CBorder(new CScrollBars(&TextView));

    // 添加"既带边框, 又带滚动条的文本视图"到窗口对象中
    WindowsObject.AddControl(pBorderScrollBars);

    // 使窗口对象绘制自身
    WindowsObject.Draw();
    printf("----------------------------------------\r\n");

    // 将"既带边框, 又带滚动条的文本视图"从窗口对象中移除
    WindowsObject.RemoveControl(pBorderScrollBars);
    delete pBorderObject;
//---------------------------//
    getchar();

    return 0;
}

总结:
修饰模式的好处在于可以在运行时刻随时随地的为某个对象添加或删去一些额外的职责, 而对象本身对此并不知情

你可能感兴趣的:(设计模式)