【描述】不修改原代碼的結構,通過裝飾器給代碼增加新功能。
【UML圖】
圖1 UML圖
(1) 原始代碼為Component類,提供了operation操作;
(2) 裝飾器為Decorator類,提供了擴展的operation功能;
(3) 注意與模板模式(設計模式(1)-模板模式(Template))的區別。
【示例代碼】
component.h
[html]
#ifndef COMPONENT_H
#define COMPONENT_H
class Component
{
public:
Component();
public:
virtual void operation();
};
#endif // COMPONENT_H
#ifndef COMPONENT_H
#define COMPONENT_H
class Component
{
public:
Component();
public:
virtual void operation();
};
#endif // COMPONENT_H
component.cpp
[html] view plaincopyprint?#include <QDebug>
#include "component.h"
Component::Component()
{
qDebug()<<"construct Component";
}
void Component::operation()
{
qDebug()<<"Base Function";
}
#include <QDebug>
#include "component.h"
Component::Component()
{
qDebug()<<"construct Component";
}
void Component::operation()
{
qDebug()<<"Base Function";
}
decorator.h
[html]
#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
#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
[html]
#include <QDebug>
#include "decorator.h"
Decorator::Decorator(Component component)
{
qDebug()<<"construct Decorator";
this->component = component;
}
void Decorator::operation()
{
component.operation();
qDebug()<<"Extend Function";
}
#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
[html]
#include "component.h"
#include "decorator.h"
int main(void)
{
Component component;
component.operation();
Decorator decorator(component);
decorator.operation();
return 0;
}
#include "component.h"
#include "decorator.h"
int main(void)
{
Component component;
component.operation();
Decorator decorator(component);
decorator.operation();
return 0;
}
【運行結果】
[html]
construct Component
Base Function
construct Component
construct Component
construct Decorator
Base Function
Extend Function
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
[html]
#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
#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
[html]
#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
}
#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
[html]
#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
#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
[html]
#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();
}
#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) 模板模式調用的代碼為
[html]
QLineEditWithIM *managerEdit;
managerEdit = new QLineEditWithIM;
QLineEditWithIM *managerEdit;
managerEdit = new QLineEditWithIM;
裝飾模式調用的代碼為
[html]
QLineEdit *_managerEdit = new QLineEdit;
managerEdit = new QLineEditWithIM(_managerEdit);
managerEdit->installIM();
QLineEdit *_managerEdit = new QLineEdit;
managerEdit = new QLineEditWithIM(_managerEdit);
managerEdit->installIM();
實質上,在模板模式中,我們並沒有使用QLineEditWithIM提供的引用對象lineEdit。而運用模板模式調用也比較簡單。可見,此處將QLineEdit想象為一個模板,運用模板模式更為合適。
作者:tandesir