前天买了《大话设计模式》,开始学习设计模式。从入公司以来,接触了一些Qt的知识,由于上学时只是浅显的学习了C语言,还自学了一点儿Java和C++,都学得很浅显,属于水过地皮都没太湿型的,没写过多少程序,所以Qt也是学得很慢,对于程序的逻辑也经常绕不过弯来,时常觉得自己很笨,后悔当初没有认真的专一的学习一门编程语言。在公司里也是整天无所事事,心中也是很不踏实,觉得自己是光吃饭不干活了。所以从现在起,要加油了努力了。先从每天看完书自己写个相应模式的小例子开始,与Qt结合,坚持写学习笔记,日积月累,相信自己会有长足的进步的。
今天学的是简单工厂模式,写了一个生产汽车各部件的例子。Ui界面如下:
功能方面,就是根据生产内容中的选择,点击确定键后在下方的文本框中显示相应的信息。
先写一个没有运用设计模式的例子,然后运用简单工厂模式对其进行改进,然后进行对比分析,最后总结在编程中遇到的一些问题。
1、没有运用设计模式的程序
makecardialog.h
#ifndef MAKECARDIALOG_H
#define MAKECARDIALOG_H
#include <QtGui/QDialog>
class QComboBox;
class QLabel;
class QTextBrowser;
class QPushButton;
class MakeCarDialog : public QDialog
{
Q_OBJECT
public:
MakeCarDialog(QWidget *parent = 0);
~MakeCarDialog();
private slots:
void resultText();
private:
QLabel *kindLabel;
QComboBox *kindComboBox;
QLabel *resultLabel;
QTextBrowser *resultTextBrowser;
QPushButton *okButton;
};
#endif
makecardialog.cpp
#include "makecardialog.h"
#include <QtGui>
MakeCarDialog::MakeCarDialog(QWidget *parent)
: QDialog(parent)
{
kindLabel = new QLabel(tr("生产内容:"));
kindComboBox = new QComboBox;
kindComboBox -> addItem(tr("大众汽车"));
kindComboBox -> addItem(tr("别克汽车"));
okButton = new QPushButton(tr("确定"));
resultLabel = new QLabel(tr("生产情况:"));
resultTextBrowser = new QTextBrowser;
QHBoxLayout *topLayout = new QHBoxLayout;
topLayout -> addWidget(kindLabel);
topLayout -> addWidget(kindComboBox, Qt::AlignLeft);
topLayout -> addWidget(okButton);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout -> addLayout(topLayout);
mainLayout -> addWidget(resultLabel);
mainLayout -> addWidget(resultTextBrowser);
setLayout(mainLayout);
setWindowTitle(tr("汽车生产V1.0"));
connect(okButton, SIGNAL(clicked()), this, SLOT(resultText()));
}
void MakeCarDialog::resultText()
{
quint8 crIndex = kindComboBox -> currentIndex();
switch(crIndex)
{
case 0:
resultTextBrowser -> append(tr("大众汽车生产中...\n大众汽车生产完毕!"));
break;
case 1:
resultTextBrowser -> append(tr("别克汽车生产中...\n别克汽车生产完毕!"));
break;
}
}
MakeCarDialog::~MakeCarDialog()
{
}
main.cpp
#include <QtGui/QApplication>
#include <QTextCodec>
#include "makecardialog.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
MakeCarDialog w;
w.show();
return a.exec();
}
2、运用简单工厂模式修改后的程序
car.h
#ifndef CAR_H
#define CAR_H
#include <QString>
class Car
{
public:
virtual QString makeCar();
};
#endif
car.cpp
#include "car.h"
#include <QObject>
QString Car::makeCar()
{
QString str = QString(QObject::tr(""));
return str;
}
buick.h
#ifndef BUICK_H
#define BUICK_H
#include "car.h"
class Buick : public Car
{
public:
virtual QString makeCar();
};
#endif
buick.cpp
#include "buick.h"
#include <QObject>
QString Buick::makeCar()
{
QString str = QString(QObject::tr("别克汽车生产中...\n"));
str += QString(QObject::tr("别克汽车生产完毕!"));
return str;
}
volkswagen.h
#ifndef VOLKSWAGEN_H
#define VOLKSWAGEN_H
#include "car.h"
class Volkswagen : public Car
{
public:
virtual QString makeCar();
};
#endif
volkswagen.cpp
#include "volkswagen.h"
#include <QObject>
QString Volkswagen::makeCar()
{
QString str = QString(QObject::tr("大众汽车生产中...\n"));
str += QString(QObject::tr("大众汽车生产完毕!"));
return str;
}
carfactory.h
#ifndef CARFACTORY_H
#define CARFACTORY_H
#include <QtGlobal>
#include "car.h"
class CarFactory
{
public:
Car *creatCar(quint8 index);
};
#endif
carfactory.cpp
#include "car.h"
#include "carfactory.h"
#include "volkswagen.h"
#include "buick.h"
Car *CarFactory::creatCar(quint8 index)
{
Car *car;
switch(index)
{
case 0:
car = new Volkswagen;
break;
case 1:
car = new Buick;
break;
}
return car;
}
makecardialog.h
#ifndef MAKECARDIALOG_H
#define MAKECARDIALOG_H
#include <QtGui/QDialog>
class QComboBox;
class QLabel;
class QTextBrowser;
class QPushButton;
class MakeCarDialog : public QDialog
{
Q_OBJECT
public:
MakeCarDialog(QWidget *parent = 0);
~MakeCarDialog();
private slots:
void resultText();
private:
QLabel *kindLabel;
QComboBox *kindComboBox;
QLabel *resultLabel;
QTextBrowser *resultTextBrowser;
QPushButton *okButton;
};
#endif
makecardialog.cpp
#include "makecardialog.h"
#include "carfactory.h"
#include "car.h"
#include "buick.h"
#include "volkswagen.h"
#include <QtGui>
MakeCarDialog::MakeCarDialog(QWidget *parent)
: QDialog(parent)
{
kindLabel = new QLabel(tr("生产内容:"));
kindComboBox = new QComboBox;
kindComboBox -> addItem(tr("大众汽车"));
kindComboBox -> addItem(tr("别克汽车"));
okButton = new QPushButton(tr("确定"));
resultLabel = new QLabel(tr("生产情况:"));
resultTextBrowser = new QTextBrowser;
QHBoxLayout *topLayout = new QHBoxLayout;
topLayout -> addWidget(kindLabel);
topLayout -> addWidget(kindComboBox, Qt::AlignLeft);
topLayout -> addWidget(okButton);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout -> addLayout(topLayout);
mainLayout -> addWidget(resultLabel);
mainLayout -> addWidget(resultTextBrowser);
setLayout(mainLayout);
setWindowTitle(tr("汽车生产V2.0"));
connect(okButton, SIGNAL(clicked()), this, SLOT(resultText()));
}
void MakeCarDialog::resultText()
{
quint8 currentIndex = kindComboBox -> currentIndex();
CarFactory *carFactory = new CarFactory;
Car *car;
car = carFactory -> creatCar(currentIndex);
resultTextBrowser -> append(car->makeCar());
}
MakeCarDialog::~MakeCarDialog()
{
}
main.cpp同前,不在重复。
两个版本的程序至此写完。
3、对比分析
未使用简单工厂模式编写的程序,业务逻辑和界面逻辑的耦合度较高。当需要添加新的生产内容时,需要改写makecardialog.cpp文件中的resultText()槽,增加相应的switch分支,这使得界面逻辑也发生了改变,而且当switch分支多到一定数量时,代码重复度也会变得很高,使得维护起来不方便。
而采用简单工厂模式编写的程序,将业务逻辑和界面逻辑分开,当需要增加新的生产内容时,只需要增加相应的子类继承Car类,并在工厂类CarFactory增加相应的switch分支即可,这些都是业务逻辑的内容,跟界面逻辑完全分离。界面方面只需增加下拉菜单的选项即可。
4、编程中遇到的问题
编译的时候出现过一个inaccessible base的错误,经过检查,是因为Volkswagen类和Buick类在继承Car类时,未指明对Car类的继承方式。而C++中类的默认继承方式是private,所以会出现此错误。