设计模式(4)-外观模式(Facade)

来源:岁月联盟 编辑:exp 时间:2012-07-10

【描述】外观模式通过在对必需的逻辑和方法的集合前创建简单的外观接口,隐藏来自调用的复杂性。

【UML图】

 

/

图1 外观模式UML图

(1) AirCondition、Fan、Light电器类定义了一个on和off的方法;

(2) Facade类定义了on和off的方法,并调用了AirCondition、Fan、Light类的on和off方法,隐藏调用的复杂性;

(3) 与组合模式的不同在于Facade和AirCondition、Fan、Light电器类是关联的关系,而不是组合的关系。

 

【示例代码】

aircondition.h

[html]
#ifndef AIRCONDITION_H 
#define AIRCONDITION_H 
 
class AirCondition 

public: 
    AirCondition(); 
    ~AirCondition(); 
 
public: 
    void on(); 
    void off(); 
}; 
 
#endif // AIRCONDITION_H 
#ifndef AIRCONDITION_H
#define AIRCONDITION_H

class AirCondition
{
public:
    AirCondition();
    ~AirCondition();

public:
    void on();
    void off();
};

#endif // AIRCONDITION_H
 
 

aircondition.cpp

[html]
#include <QDebug> 
#include "aircondition.h" 
 
AirCondition::AirCondition() 

    qDebug()<<"construct AirCondition"; 

 
AirCondition::~AirCondition() 

    qDebug()<<"destruct AirCondition"; 

 
void AirCondition::on() 

    qDebug()<<"AirCondition on"; 

 
void AirCondition::off() 

    qDebug()<<"AirCondition off"; 

#include <QDebug>
#include "aircondition.h"

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

AirCondition::~AirCondition()
{
    qDebug()<<"destruct AirCondition";
}

void AirCondition::on()
{
    qDebug()<<"AirCondition on";
}

void AirCondition::off()
{
    qDebug()<<"AirCondition off";
}
 

fan.h

[html]
#ifndef FAN_H 
#define FAN_H 
 
class Fan 

public: 
    Fan(); 
    ~Fan(); 
 
public: 
    void on(); 
    void off(); 
}; 
 
#endif // FAN_H 
#ifndef FAN_H
#define FAN_H

class Fan
{
public:
    Fan();
    ~Fan();

public:
    void on();
    void off();
};

#endif // FAN_H
 

fan.cpp

[html]
#include <QDebug> 
#include "fan.h" 
 
Fan::Fan() 

    qDebug()<<"construct Fan"; 

 
Fan::~Fan() 

    qDebug()<<"destruct Fan"; 

 
void Fan::on() 

    qDebug()<<"Fan on"; 

 
void Fan::off() 

    qDebug()<<"Fan off"; 

#include <QDebug>
#include "fan.h"

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

Fan::~Fan()
{
    qDebug()<<"destruct Fan";
}

void Fan::on()
{
    qDebug()<<"Fan on";
}

void Fan::off()
{
    qDebug()<<"Fan off";
}
 

light.h

[html]
#ifndef LIGHT_H 
#define LIGHT_H 
 
class Light 

public: 
    Light(); 
    ~Light(); 
 
public: 
    void on(); 
    void off(); 
}; 
 
#endif // LIGHT_H 
#ifndef LIGHT_H
#define LIGHT_H

class Light
{
public:
    Light();
    ~Light();

public:
    void on();
    void off();
};

#endif // LIGHT_H
 

light.cpp

[html]
#include <QDebug> 
#include "light.h" 
 
Light::Light() 

    qDebug()<<"construct Light"; 

 
Light::~Light() 

    qDebug()<<"destruct Light"; 

 
void Light::on() 

    qDebug()<<"Light on"; 

 
void Light::off() 

    qDebug()<<"Light off"; 

#include <QDebug>
#include "light.h"

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

Light::~Light()
{
    qDebug()<<"destruct Light";
}

void Light::on()
{
    qDebug()<<"Light on";
}

void Light::off()
{
    qDebug()<<"Light off";
}
 

facade.h

[html]
#ifndef FACADE_H 
#define FACADE_H 
 
#include "aircondition.h" 
#include "fan.h" 
#include "light.h" 
 
class Facade 

public: 
    Facade(); 
    ~Facade(); 
 
private: 
    AirCondition *_airCondition; 
    Fan *_fan; 
    Light *_light; 
 
public: 
    void on(); 
    void off(); 
}; 
 
#endif // FACADE_H 
#ifndef FACADE_H
#define FACADE_H

#include "aircondition.h"
#include "fan.h"
#include "light.h"

class Facade
{
public:
    Facade();
    ~Facade();

private:
    AirCondition *_airCondition;
    Fan *_fan;
    Light *_light;

public:
    void on();
    void off();
};

#endif // FACADE_H
 

facade.cpp

[html]
#include <QDebug> 
#include "facade.h" 
 
Facade::Facade() 

    qDebug()<<"construct Facade"; 
 
    _airCondition = new AirCondition; 
    _fan = new Fan; 
    _light = new Light; 

 
Facade::~Facade() 

    qDebug()<<"destruct Facade"; 
 
    delete _airCondition; 
    delete _fan; 
    delete _light; 

 
void Facade::on() 

    qDebug()<<"Facade::on"; 
 
    _airCondition->on(); 
    _fan->on(); 
    _light->on(); 

 
void Facade::off() 

    qDebug()<<"Facade::off"; 
 
    _airCondition->off(); 
    _fan->off(); 
    _light->off(); 

#include <QDebug>
#include "facade.h"

Facade::Facade()
{
    qDebug()<<"construct Facade";

    _airCondition = new AirCondition;
    _fan = new Fan;
    _light = new Light;
}

Facade::~Facade()
{
    qDebug()<<"destruct Facade";

    delete _airCondition;
    delete _fan;
    delete _light;
}

void Facade::on()
{
    qDebug()<<"Facade::on";

    _airCondition->on();
    _fan->on();
    _light->on();
}

void Facade::off()
{
    qDebug()<<"Facade::off";

    _airCondition->off();
    _fan->off();
    _light->off();
}
 

main.cpp

[html] view plaincopyprint?#include "facade.h" 
 
int main(void) 

    Facade *facade = new Facade; 
    facade->on(); 
    facade->off(); 
 
    return 0; 

#include "facade.h"

int main(void)
{
    Facade *facade = new Facade;
    facade->on();
    facade->off();

    return 0;
}
 

【运行结果】

[html]
construct Facade  
construct AirCondition  
construct Fan  
construct Light  
Facade::on  
AirCondition on  
Fan on  
Light on  
Facade::off  
AirCondition off  
Fan off  
Light off 
construct Facade
construct AirCondition
construct Fan
construct Light
Facade::on
AirCondition on
Fan on
Light on
Facade::off
AirCondition off
Fan off
Light off
 
 

【结果分析】
Facade的on方法为电器类on方法的集合提供了接口,可以根据需要定义不同的on方法。

 

【实例剖析】

外观模式是我们常用的设计模式,有时候不知不觉就用到了。看下面一个登陆界面的设计实例。

先看UML图,

 

/

图2

(1) LoginDlg继承了QDialog类,实现用户登录鉴权;

(2) LoginDlg调用了QLabel、QLineEdit进行界面设计,界面设计的代码单独分离,构建了外观方法,提供给构造函数调用;

(3) 提供了cancel方法,cancel调用了QLineEdit相关对象的clear方法,实质上是一个外观打包。

 

【代码清单】

[html]
LoginDlg::LoginDlg() 

    //qDebug()<<"construct_login"; 
    initDlg(); 
    initConnect(); 

 
LoginDlg::~LoginDlg() 

    delete label_username; 
    delete label_passwd; 
    delete lineEdit_username; 
    delete lineEdit_passwd; 
    delete pushButton_ok; 
    delete pushButton_cancel; 
 
    //qDebug()<<"desstruct_login"; 

 
void LoginDlg::initDlg() 

    setWindowFlags(Qt::FramelessWindowHint); 
    label_username = new QLabel; 
    label_username->setText(tr("用 户 名:")); 
    label_passwd = new QLabel; 
    label_passwd->setText(tr("用户密码:")); 
    lineEdit_username = new QLineEdit; 
    lineEdit_username->setFocus(); 
    lineEdit_passwd = new QLineEdit; 
    lineEdit_passwd->setEchoMode(QLineEdit::Password); 
 
    pushButton_ok = new QPushButton; 
    pushButton_ok->setText(tr("确定")); 
    pushButton_ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton)); 
    pushButton_cancel = new QPushButton; 
    pushButton_cancel->setText(tr("取消")); 
    pushButton_cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton)); 
 
    QGridLayout *gridLayout = new QGridLayout; 
    gridLayout->addWidget(label_username,0,0); 
    gridLayout->addWidget(lineEdit_username,0,1); 
    gridLayout->addWidget(label_passwd,1,0); 
    gridLayout->addWidget(lineEdit_passwd,1,1); 
 
    QHBoxLayout *buttonLayout = new QHBoxLayout; 
    buttonLayout->addStretch(); 
    buttonLayout->addWidget(pushButton_ok); 
    buttonLayout->addStretch(); 
    buttonLayout->addWidget(pushButton_cancel); 
    buttonLayout->addStretch(); 
 
    QVBoxLayout *mainLayout = new QVBoxLayout; 
    mainLayout->addLayout(gridLayout); 
    mainLayout->addLayout(buttonLayout); 
    mainLayout->addStretch(); 
 
    setLayout(mainLayout); 

 
void LoginDlg::initConnect() 

    connect(pushButton_cancel,SIGNAL(clicked()),this,SLOT(cancel())); 
    connect(pushButton_ok,SIGNAL(clicked()),this,SLOT(Login())); 

 
void LoginDlg::cancel() 

    lineEdit_username->clear(); 
    lineEdit_passwd->clear(); 
 
    close(); 

LoginDlg::LoginDlg()
{
    //qDebug()<<"construct_login";
    initDlg();
    initConnect();
}

LoginDlg::~LoginDlg()
{
    delete label_username;
    delete label_passwd;
    delete lineEdit_username;
    delete lineEdit_passwd;
    delete pushButton_ok;
    delete pushButton_cancel;

    //qDebug()<<"desstruct_login";
}

void LoginDlg::initDlg()
{
    setWindowFlags(Qt::FramelessWindowHint);
    label_username = new QLabel;
    label_username->setText(tr("用 户 名:"));
    label_passwd = new QLabel;
    label_passwd->setText(tr("用户密码:"));
    lineEdit_username = new QLineEdit;
    lineEdit_username->setFocus();
    lineEdit_passwd = new QLineEdit;
    lineEdit_passwd->setEchoMode(QLineEdit::Password);

    pushButton_ok = new QPushButton;
    pushButton_ok->setText(tr("确定"));
    pushButton_ok->setIcon(style()->standardIcon(QStyle::SP_DialogOkButton));
    pushButton_cancel = new QPushButton;
    pushButton_cancel->setText(tr("取消"));
    pushButton_cancel->setIcon(style()->standardIcon(QStyle::SP_DialogCancelButton));

    QGridLayout *gridLayout = new QGridLayout;
    gridLayout->addWidget(label_username,0,0);
    gridLayout->addWidget(lineEdit_username,0,1);
    gridLayout->addWidget(label_passwd,1,0);
    gridLayout->addWidget(lineEdit_passwd,1,1);

    QHBoxLayout *buttonLayout = new QHBoxLayout;
    buttonLayout->addStretch();
    buttonLayout->addWidget(pushButton_ok);
    buttonLayout->addStretch();
    buttonLayout->addWidget(pushButton_cancel);
    buttonLayout->addStretch();

    QVBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addLayout(gridLayout);
    mainLayout->addLayout(buttonLayout);
    mainLayout->addStretch();

    setLayout(mainLayout);
}

void LoginDlg::initConnect()
{
    connect(pushButton_cancel,SIGNAL(clicked()),this,SLOT(cancel()));
    connect(pushButton_ok,SIGNAL(clicked()),this,SLOT(Login()));
}

void LoginDlg::cancel()
{
    lineEdit_username->clear();
    lineEdit_passwd->clear();

    close();
}

 

LoginDlg类中initDlg、cancel方法,应用了外观模式。cancel方法运用了多态特性,覆盖了LoginDlg的父类QDialog的cancel方法,是LoginDlg类的一个私有槽函数。外观模式的应用使得构造函数更为清晰,initConnect方法更为简单。这时可以利用:

[html]
connect(pushButton_cancel,SIGNAL(clicked()),this,SLOT(cancel())); 
connect(pushButton_cancel,SIGNAL(clicked()),this,SLOT(cancel()));
来取代

[html] view plaincopyprint?connect(pushButton_cancel,SIGNAL(clicked()),lineEdit_username,SLOT(clear())); 
connect(pushButton_cancel,SIGNAL(clicked()),lineEdit_passwd,SLOT(clear())); 
connect(pushButton_cancel,SIGNAL(clicked()),this,SLOT(close())); 
connect(pushButton_cancel,SIGNAL(clicked()),lineEdit_username,SLOT(clear()));
connect(pushButton_cancel,SIGNAL(clicked()),lineEdit_passwd,SLOT(clear()));
connect(pushButton_cancel,SIGNAL(clicked()),this,SLOT(close()));

将界面设计的代码从构造函数中,单独分离,也是一种好的设计方式。

 

*对外观模式有更好的见解,欢迎留言,交流学习。

 

 作者:tandesir