程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 設計模式(5)-裝飾模式(Decorator)

設計模式(5)-裝飾模式(Decorator)

編輯:C++入門知識

【描述】不修改原代碼的結構,通過裝飾器給代碼增加新功能。

【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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved