您的位置:首页 > 其它

设计模式(5)-装饰模式(Decorator)

2012-07-09 15:52 204 查看
【描述】不修改原代码的结构,通过装饰器给代码增加新功能。

【UML图】



图1 UML图
(1) 原始代码为Component类,提供了operation操作;
(2) 装饰器为Decorator类,提供了扩展的operation功能;
(3) 注意与模板模式(设计模式(1)-模板模式(Template))的区别。

【示例代码】
component.h
#ifndef COMPONENT_H
#define COMPONENT_H

class Component
{
public:
    Component();

public:
    virtual void operation();
};

#endif // COMPONENT_H


component.cpp
#include <QDebug>
#include "component.h"

Component::Component()
{
    qDebug()<<"construct Component";
}

void Component::operation()
{
    qDebug()<<"Base Function";
}


decorator.h
#ifndef DECORATOR_H
#define DECORATOR_H

#include "component.h"

class Decorator : public Component
{
public:
    Decorator(Component component);

private:
    Component component;

public:
    void operation();
};

#endif // DECORATOR_H


decorator.cpp
#include <QDebug>
#include "decorator.h"

Decorator::Decorator(Component component)
{
    qDebug()<<"construct Decorator";
    this->component = component;
}

void Decorator::operation()
{
    component.operation();
    qDebug()<<"Extend Function";
}


main.cpp
#include "component.h"
#include "decorator.h"

int main(void)
{
    Component component;
    component.operation();
    Decorator decorator(component);
    decorator.operation();

    return 0;
}


【运行结果】
construct Component 
Base Function 
construct Component 
construct Component 
construct Decorator 
Base Function 
Extend Function


【结果分析】
借助装饰器,在没有改变原始代码的前提下,给代码增加了新功能。

【实例剖析】
设计模式(1)-模板模式(Template)一文介绍了一种改进的Qt嵌入式输入法,下面利用装饰模式对代码进行改写。先看UML图:



图2
(1) 原始代码为QLineEdit类;
(2) 装饰器为QLineEditWithIM类,提供了installIM()方法。

【代码清单】
下面仅贴出修改的部分,详细代码请参考Qt输入法设计(嵌入式)以及设计模式(1)-模板模式(Template)一文。
qlineeditwithim.h
#ifndef QLINEEDITWITHIM_H
#define QLINEEDITWITHIM_H

#include <QLineEdit>
#include "inputmethod.h"

class QLineEditWithIM : public QLineEdit
{
public:
    QLineEditWithIM(QLineEdit *lineEdit);
    ~QLineEditWithIM();

private:
    QLineEdit *lineEdit;
    InputMethod *im;

public:
    void installIM();
};

#endif // QLINEEDITWITHIM_H


qlineeditwithim.cpp
#include "qlineeditwithim.h"

QLineEditWithIM::QLineEditWithIM(QLineEdit *lineEdit)
{
//#ifdef Q_WS_QWS
    im = new InputMethod;
    this->lineEdit = lineEdit;
//#endif
}

QLineEditWithIM::~QLineEditWithIM()
{
    delete im;
}

void QLineEditWithIM::installIM()
{
//#ifdef Q_WS_QWS
    installEventFilter(im);
    connect(im->keyboard,SIGNAL(setvalue(QString)),this,SLOT(setText(QString)));
//#endif
}


login.h
#ifndef LOGIN_H
#define LOGIN_H

#include <QDialog>
#include "qlineeditwithim.h"

class QLabel;
class QLineEdit;
class QDialogButtonBox;

class QLogin : public QDialog
{
    Q_OBJECT

public:
    QLogin();
    ~QLogin();

public:

    QLabel *managerLabel;
    QLabel *passwdLabel;

    QLineEditWithIM *managerEdit;
    QLineEditWithIM *passwdEdit;

    QPushButton *okButton;
    QPushButton *cancelButton;
    QDialogButtonBox *buttonBox;

signals:
    void Authorize();

private slots:
    void login();
    void cancel();

};

#endif // LOGIN_H


login.cpp
#include <QtGui>
#include "login.h"

QLogin::QLogin()
{
    managerLabel = new QLabel(tr("&Manager:"));
    QLineEdit *_managerEdit = new QLineEdit;
    managerEdit = new QLineEditWithIM(_managerEdit);
    managerEdit->installIM();
    managerLabel->setBuddy(managerEdit);

    passwdLabel = new QLabel(tr("&Passwd:"));
    QLineEdit *_passwdEdit = new QLineEdit;
    passwdEdit = new QLineEditWithIM(_passwdEdit);
    passwdEdit->installIM();
    passwdEdit->setEchoMode(QLineEdit::Password);
    passwdLabel->setBuddy(passwdEdit);

    okButton = new QPushButton(tr("&Login"));
    cancelButton = new QPushButton("&Cancel");

    okButton->setDefault(true);

    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(okButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(cancelButton, QDialogButtonBox::AcceptRole);

    connect(okButton, SIGNAL(clicked()), this, SLOT(login()));
    connect(cancelButton, SIGNAL(clicked()), this, SLOT(cancel()));

    QHBoxLayout *topLayout = new QHBoxLayout;
    topLayout->addWidget(managerLabel);
    topLayout->addWidget(managerEdit);

    QHBoxLayout *midLayout = new QHBoxLayout;
    midLayout->addWidget(passwdLabel);
    midLayout->addWidget(passwdEdit);

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(topLayout);
    mainLayout->addLayout(midLayout);
    mainLayout->addWidget(buttonBox);
    mainLayout->setMargin(20);
    setLayout(mainLayout);
    managerEdit->setFocus();  

    QIcon icon;
    icon.addFile(QString::fromUtf8(":/new/main/picture/logo.png"), QSize(), QIcon::Normal, QIcon::Off);
    setWindowIcon(icon);
    setWindowTitle("Login");
}

QLogin::~QLogin()
{
    qDebug()<<"destruct login";
    delete managerLabel;
    delete managerEdit;
    delete passwdLabel;
    delete passwdEdit;
    delete okButton;
    delete cancelButton;
}

/*
* Name : void login()
* Type : slot
* Func : login when authorize
* In   : Null
* Out  : Null
*/
void QLogin::login()
{
    qDebug()<<managerEdit->text();
    qDebug()<<passwdEdit->text();
}

/*
* Name : void cancel()
* Type : slot
* Func : cancel login
* In   : Null
* Out  : Null
*/
void QLogin::cancel()
{
    managerEdit->clear();
    passwdEdit->clear();
    close();
}


【分析】
(1) 与模板模式的关键区别在于,QLineEditWithIM引用了QLineEdit对象;
(2) 模板模式调用的代码为
QLineEditWithIM *managerEdit;  
managerEdit = new QLineEditWithIM;

装饰模式调用的代码为
QLineEdit *_managerEdit = new QLineEdit;
managerEdit = new QLineEditWithIM(_managerEdit);
managerEdit->installIM();

实质上,在模板模式中,我们并没有使用QLineEditWithIM提供的引用对象lineEdit。而运用模板模式调用也比较简单。可见,此处将QLineEdit想象为一个模板,运用模板模式更为合适。

【学习参考】
(1) Qt输入法设计(嵌入式)
(2) 设计模式(1)-模板模式(Template))

【源码下载】
1 http://download.csdn.net/detail/tandesir/4418929
2 Qt设计模式1-8测试源码:http://download.csdn.net/detail/tandesir/4984275

声明:该源码仅供学习交流,勿用于商业目的。

转载请标明出处,仅供学习交流,勿用于商业目的

Copyright @ http://blog.csdn.net/tandesir
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: