您的位置:首页 > 其它

设计模式(1)-模板模式(Template)

2012-06-06 16:43 441 查看
【更新】

2012-7-9,设计模式(5)-装饰模式(Decorator),运用装饰模式的版本

2012-6-18,添加实例下载地址,文章末尾

2012-6-8,更新示例代码

【描述】模板设计模式将常用的方法进行封装,创建了一个实施一组方法和功能的抽象的对象。子类通常将这个对象作为模板用于设计。

【UML图】





图1 UML图
1 DrawTemplate有三个抽象的方法:draw() - (protected)、getMethod() - (public)、setMethod() - (protected、纯虚函数-接口)
2 Draw1和Draw2继承了DrawTemplate,Draw1对draw()方法进行了重载、重用了DrawTemplate类的getMethod()方法,实现了setMethod接口。Draw2对draw()、getMethod()方法进行了重载,实现了setMethod接口。
3 对方法的重用是模板模式的优点,如Draw1重用了DrawTemplate类的getMethod方法

【示例代码】
drawtemplate.h
#ifndef DRAWTEMPLATE_H
#define DRAWTEMPLATE_H

#include <QString>
class DrawTemplate
{
public:
    DrawTemplate();

protected:
    virtual void draw();
    virtual void setMethod(QString method) const = 0;
    
public:
    virtual QString getMethod();
};

#endif // DRAWTEMPLATE_H


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

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

void DrawTemplate::draw()
{
    qDebug()<<"DrawTemplate::draw()";
    setMethod(getMethod());
}

QString DrawTemplate::getMethod()
{
    QString test = "Method::DrawTemplate";
    qDebug()<<"DrawTemplate::getMethod()";
    return test;
}


draw1.h
#ifndef DRAW1_H
#define DRAW1_H

#include "drawtemplate.h"

class Draw1 : public DrawTemplate
{
public:
    Draw1();

public:
    void draw();

    void setMethod(QString) const;
};

#endif // DRAW1_H


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

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

void Draw1::draw()
{
    qDebug()<<"Draw1::draw()";
    setMethod(getMethod());
}

void Draw1::setMethod(QString method) const
{
    qDebug()<<QString("Draw1::setMethod(%1)").arg(method);
}


draw2.h
#ifndef DRAW2_H
#define DRAW2_H

#include "drawtemplate.h"

class Draw2 : public DrawTemplate
{
public:
    Draw2();

public:
    void draw();

    QString getMethod();
    void setMethod(QString method) const;
};

#endif // DRAW2_H


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

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

void Draw2::draw()
{
    qDebug()<<"Draw2::draw()";
    setMethod(getMethod());
}

QString Draw2::getMethod()
{
    QString test = "Method::Draw2";
    qDebug()<<"Draw2::getMethod()";
    return test;
}

void Draw2::setMethod(QString method) const
{
    qDebug()<<QString("Draw2::setMethod(%1)").arg(method);
}


main.cpp
#include "drawtemplate.h"
#include "draw1.h"
#include "draw2.h"

int main(void)
{
    Draw1 draw1;
    draw1.draw();

    Draw2 draw2;
    draw2.draw();
}


【运行结果】
construct DrawTemplate 
construct Draw1 
Draw1::draw() 
DrawTemplate::getMethod() 
"Draw1::setMethod(Method::DrawTemplate)" 
construct DrawTemplate 
construct Draw2 
Draw2::draw() 
Draw2::getMethod() 
"Draw2::setMethod(Method::Draw2)"


【实例剖析】
*该实例不是严格的模板模式,因为并没有覆盖模板中的方法。有好的见解,欢迎留言!(2012-09-06)
Qt输入法设计(嵌入式)一文中介绍了一种输入法的设计,在使用时,需要对控件对象的名称进行指定,并对每个QLineEdit对象绑定输入法对象。能否有一种方法,使得编辑框自带输入法对象?
下面利用模板模式,将QLineEdit作为模板,派生一个QLineEditWithIM,使得QLineEditWithIM自带输入法,使用就像QLineEdit一样简单。UML图如图2所示:



图2
【代码清单】
仅贴出改动的部分,省略了keyboard.h、keyboard.cpp代码。详请参考Qt输入法设计(嵌入式)
inputmethod.h
#ifndef INPUTMETHOD_H
#define INPUTMETHOD_H

#include "keyboard.h"

class InputMethod : public KeyBoard
{
    Q_OBJECT
public:
    InputMethod();
    ~InputMethod();

    bool eventFilter(QObject *obj, QEvent *event);

public:
    KeyBoard *keyboard;

public:
    void showKeyBoard();
};

#endif // INPUTMETHOD_H


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

InputMethod::InputMethod()
{
    keyboard = new KeyBoard;
    setWindowFlags(Qt::Tool|Qt::WindowStaysOnTopHint|Qt::FramelessWindowHint);
}

InputMethod::~InputMethod()
{
    delete keyboard;
}

/*
* Name : void eventFilter(QObject *obj, QEvent *event);
* Type : QEvent
* Func : judge input method event
* In   : QObject,QEvent
* Out  : bool
*/
bool InputMethod::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type()==QEvent::MouseButtonPress)
    {
        showKeyBoard();
        return true;
    }

    return QObject::eventFilter(obj,event);
}

/*
* Name : void showKeyBoard();
* Type : function
* Func : show keyBoard
* In   : Null
* Out  : Null
*/
void InputMethod::showKeyBoard()
{
    keyboard->setWindowFlags(Qt::Tool|Qt::WindowStaysOnTopHint|Qt::FramelessWindowHint);
    keyboard->move(50,120);
    keyboard->exec();
}


qlineeditwithim.h
#ifndef QLINEEDITWITHIM_H
#define QLINEEDITWITHIM_H

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

class QLineEditWithIM : public QLineEdit
{
public:
    QLineEditWithIM();

private:
    InputMethod *im;
};

#endif // QLINEEDITWITHIM_H


qlineeditwithim.cpp
#include "qlineeditwithim.h"

QLineEditWithIM::QLineEditWithIM()
{
//#ifdef Q_WS_QWS
    im = new InputMethod;
    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:"));
    managerEdit = new QLineEditWithIM();
    managerLabel->setBuddy(managerEdit);

    passwdLabel = new QLabel(tr("&Passwd:"));
    passwdEdit = new QLineEditWithIM;
    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()<<"login close";
    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();
}


main.cpp
#include <QtGui/QApplication>
#include "login.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QLogin login;
    login.show();
    return app.exec();
}



【分析】
1 改动后,省去了繁杂的调用步骤,只要采用
QLineEditWithIM *managerEdit;
managerEdit = new QLineEditWithIM;

替代
QLineEdit *managerEdit;
managerEdit = new QLineEdit;

在鼠标单击时,就可以弹出输入法了。

2 去掉qlineeditwithim.cpp中注释,即改为
#include "qlineeditwithim.h"

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

在嵌入式版本中将弹出输入法,其他版本不会弹出输入法。

3 QLineEditWithIM重用了QLineEdit的方法,并增加了嵌入式输入法功能。而且没有增加任何调用开销。


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

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



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

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