界面与逻辑
基本程序架构一般包含:
—用户界面模块(UI)
接受用户输入及呈现数据
—业务逻辑模块(Business Logic)
根据用户需求处理数据
用户界面与业务逻辑如何交互?
基本设计原则
功能模块之间需要进行解耦
核心思想:强内聚,弱耦合
-每个模块应该只实现单一的功能
-模块内部的子模块只为整体的单一功能而存在
-模块之间通过约定好的接口进行交互
QCalculatorUI(接收用户的输入,并呈现最终的结果)和QCalculatorDec(实现计算器的核心算法)这两个类没有什么关系,都依赖于顶层的接口ICalculator
QCalculator的作用就是将QCalculatorUI和QCalculatorDec这两个类通过接口ICalculator结合在一起。
现在需要做的就是定义一个接口,并且定义一个QCalculator这个类
在C++中没有接口的概念,但是我们可以通过纯虚类来进行实现。
ICalculator.h
#ifndef _ICALCULATOR_H
#define _ICALCULATOR_H
#include <QString>
class ICalculator
{
public:
virtual bool expression(const QString& exp) = 0; //接收用户输入
virtual QString result() = 0; //呈现输出结果
};
#endif // ICALCULATOR_H
添加QCalculaor.h类
#ifndef QCALCULATOR_H
#define QCALCULATOR_H
#include"QCalculatorUI.h"
#include "QCalculatorDec.h"
class QCalculator
{
protected:
QCalculatorUI* m_ui; //UI这个类使用的是二阶构造来构造的,如果有一个成员变量它使用的是二阶构造来完成的,使用该成员变量整体的类也需要使用二阶构造。
QCalculatorDec m_cal;
QCalculator();
bool construct();
public:
static QCalculator* NewInstance();
void show();//用来调用UI的show函数
~QCalculator();
};
#endif // QCALCULATOR_H
#include "QCalculator.h"
QCalculator::QCalculator()
{
}
bool QCalculator::construct()
{
m_ui = QCalculatorUI::NewInstance();
return (m_ui != NULL);
}
QCalculator* QCalculator::NewInstance()
{
QCalculator* ret = new QCalculator();
if((ret == NULL) || !ret->construct() )
{
delete ret;
ret = NULL;
}
return ret;
}
void QCalculator::show()
{
m_ui->show();
}
QCalculator::~QCalculator()
{
delete m_ui;
}
上面仅仅是添加了两个类,并没有实现QCalculatorUI对IQCalculator的依赖,下面来做这件事。
实现UI与接口的关联
#ifndef _QCALCULATORUI_H_
#define _QCALCULATORUIH_
#include <QWidget>
#include <QPushButton>
#include <QLineEdit>
#include "iCalculator.h"
class QCalculatorUI : public QWidget
{
Q_OBJECT
private:
QLineEdit* m_edit;
QPushButton* m_buttons[20];
ICalculator* m_cal;
QCalculatorUI();
bool construct();
private slots:
void onButtonClicked();
public:
static QCalculatorUI* NewInstance();
void show();
~QCalculatorUI();
void setCalculator(ICalculator* cal);
ICalculator* getCalculator();
};
#endif // _QCALCULATORUI_H_
QCalculatorUI.cpp
#include "QCalculatorUI.h"
#include <QDebug>
QCalculatorUI::QCalculatorUI(): QWidget(NULL,Qt::WindowCloseButtonHint) //此处QCalculatorUI就是作为顶层窗口存在的,虽然这个地方继承自QWidget,但是赋值为NULL,相当于它是没有父类的(但是实际上还是有的)。
//将窗口中的最大化和最小化去掉
{
//因为QLineEdit与QCalculatorUI以及QPushButton与QCalculatorUI是组合关系,那么就应该同生死,因此需要在构造函数对其定义。因为此处涉及到在堆上申请内存空间,因此需要
//使用二阶构造
m_cal = NULL;
}
bool QCalculatorUI::construct()
{
bool ret = true;
const char* btnText[20] =
{
"7", "8", "9", "+", "(",
"4", "5", "6", "-", ")",
"1", "2", "3", "*", "<-",
"0", ".", "=", "/", "C",
};
m_edit = new QLineEdit(this);
if(m_edit != NULL)
{
m_edit->move(10,10);
m_edit->resize(240,30);
m_edit->setReadOnly(true); //使QLineEdit只读
m_edit->setAlignment(Qt::AlignRight); //使字符串靠右对齐
}
else
{
ret = false;
}
for(int i=0; (i<4) && ret; i++)
{
for(int j=0; (j<5) && ret; j++)
{
if(m_buttons[i*5 + j] != NULL)
{
m_buttons[i*5 + j] = new QPushButton(this);
m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);
m_buttons[i*5 + j]->resize(40,40);
m_buttons[i*5 + j]->setText(btnText[i*5 + j]);
connect(m_buttons[i*5 + j],SIGNAL(clicked()), this, SLOT(onButtonClicked()));
}
else
{
ret = false;
}
}
}
return ret;
}
QCalculatorUI* QCalculatorUI::NewInstance()
{
QCalculatorUI* ret = new QCalculatorUI();
if((ret == NULL) || !(ret->construct()))
{
delete ret;
ret = NULL;
}
return ret;
}
void QCalculatorUI::onButtonClicked()
{
QPushButton* btn = dynamic_cast<(QPushButton*)>(sender());
QString clickText = btn->text();
if(btn !=NULL)
{
if(clickText == "<-")//此时应该将字符串的最后一个字符去掉。
{
QString text = m_edit->text();
if(text.length() > 0)
{
text.remove(text.length()-1,1);
m_edit->setText(text);
}
}
else if(clickText == "C")
{
m_edit->setText( "");
}
else if(clickText == "=")
{
if(m_cal != NULL)
{
m_cal->expression(m_edit->text());
m_edit->setText(m_cal->result());
}
}
else
{
m_edit->setText(m_edit->text() + clickText);
}
}
}
void QCalculatorUI::show()
{
QWidget::show();
this->setFixedSize(this->width(),this->height()); //固定窗口的大小
}
QCalculatorUI::~QCalculatorUI()
{
}
void QCalculatorUI:: setCalculator(ICalculator* cal)
{
m_cal = cal;
}
ICalculator* QCalculatorUI::getCalculator()
{
return m_cal;
}
实现核心算法与接口的关联
因为在QCalculatorDec.h中已经实现了result和expression函数,因此只需要将QCalculatorDec这个类继承于ICalculator这个类就行。
如何将UI与核心算法进行间接关联呢?
#include "QCalculator.h"
QCalculator::QCalculator()
{
}
bool QCalculator::construct()
{
m_ui = QCalculatorUI::NewInstance();
if(m_ui != NULL)
{
m_ui->setCalculator(&m_cal); //将UI和核心算法关联在一起了,这样的关联是通过接口进行的。从代码上看,
//UI与算法并没有产生直接的关系。
}
return (m_ui != NULL);
}
QCalculator* QCalculator::NewInstance()
{
QCalculator* ret = new QCalculator();
if((ret == NULL) || !ret->construct() )
{
delete ret;
ret = NULL;
}
return ret;
}
void QCalculator::show()
{
m_ui->show();
}
QCalculator::~QCalculator()
{
delete m_ui;
}
小结: