用户界面与业务逻辑如何交互?
功能模块之间需要进行解耦
核心思想:高内聚,低耦合
在工程开发中接口是什么?
用户界面与业务逻辑的交互

模块之间仅通过接口进行关联
模块间的关系是单项依赖的
计算器应用程序的整体架构

/* ICalculator.h 接口纯虚类 */
#include "QCalculator.h"
QCalculator::QCalculator() {
}
bool QCalculator::construct() {
m_ui = QCalculatorUI::NewInstance();
if (m_ui != NULL) {
m_ui->setCalculator(&m_cal);
}
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.h */
#ifndef QCALCULATORUI_H
#define QCALCULATORUI_H
#include <QWidget>
#include <QLineEdit>
#include <QPushButton>
#include "ICalculator.h"
#define SPACE 10
#define LINEEDIT_HEIGHT 45
#define WIDTH 60
#define HEIGHT 60
#define ROW 4
#define COL 5
class QCalculatorUI : public QWidget
{
Q_OBJECT
private:
QLineEdit* m_edit;
QPushButton* m_button[20];
ICalculator* m_cal;
QCalculatorUI();
bool construct();
public:
static QCalculatorUI* NewInstance();
void show();
void setCalculator(ICalculator* cal);
ICalculator* getCalculator();
~QCalculatorUI();
private slots:
void onButtonClicked();
};
#endif // QCALCULATORUI_H
/* QCalculatorUI.cpp */
#include "QCalculatorUI.h"
#include <QDebug>
QCalculatorUI::QCalculatorUI() : QWidget(NULL, Qt::WindowCloseButtonHint) {
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(SPACE, SPACE);
m_edit->resize(5*WIDTH+4*SPACE, LINEEDIT_HEIGHT);
m_edit->setReadOnly(true);
m_edit->setAlignment(Qt::AlignRight);
}
else {
ret = false;
}
for (int i = 0; (i < ROW) && ret; i++) {
for (int j = 0; (j < COL) && ret; j++) {
m_button[i*COL+j] = new QPushButton(this);
if (m_button[i*COL+j] != NULL) {
m_button[i*COL+j]->resize(WIDTH, HEIGHT);
m_button[i*COL+j]->move(SPACE+(SPACE+WIDTH)*j, SPACE+SPACE+LINEEDIT_HEIGHT+(SPACE+WIDTH)*i);
m_button[i*COL+j]->setText(btnText[i*COL+j]);
connect(m_button[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::show() {
QWidget::show();
this->setFixedSize(this->width(), this->height());
}
void QCalculatorUI::setCalculator(ICalculator *cal) {
m_cal = cal;
}
ICalculator *QCalculatorUI::getCalculator() {
return m_cal;
}
QCalculatorUI::~QCalculatorUI() {
}
void QCalculatorUI::onButtonClicked() {
// 获取信号的发送者
QPushButton* btn = dynamic_cast<QPushButton*>(sender());
if (btn != NULL) {
qDebug() << btn->text();
QString clickText = btn->text();
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);
}
}
}
/* QCalculatorDec.h */
#ifndef QCALCULATORDEC_H
#define QCALCULATORDEC_H
#include <QString>
#include <QQueue>
#include <QStack>
#include "ICalculator.h"
class QCalculatorDec : public ICalculator
{
protected:
QString m_result;
bool isDigitOrDot(QChar c);
bool isSymbol(QChar c);
bool isSign(QChar c);
bool isNumber(QString s);
bool isOperator(QString s);
bool isLeft(QString s);
bool isRight(QString s);
int priority(QString s);
bool match(QQueue<QString>& exp);
QString calculate(QQueue<QString>& exp);
QString calculate(const QString& l, const QString& op, const QString& r);
bool transform(QQueue<QString>& exp, QQueue<QString>& output);
QQueue<QString> split(const QString& exp);
public:
QCalculatorDec();
bool expression(const QString& exp);
QString result();
};
#endif // QCALCULATORDEC_H
/* QCalculatorDec.cpp */
#include "QCalculatorDec.h"
#include <QDebug>
bool QCalculatorDec::isDigitOrDot(QChar c) {
return (('0' <= c) && (c <= '9')) || (c == '.');
}
bool QCalculatorDec::isSymbol(QChar c) {
return isOperator(c) || (c == '(') || (c == ')');
}
bool QCalculatorDec::isSign(QChar c) {
return (c == '+') || (c == '-');
}
bool QCalculatorDec::isNumber(QString s) {
bool ret = false;
s.toDouble(&ret);
return ret;
}
bool QCalculatorDec::isLeft(QString s) {
return (s == "(");
}
bool QCalculatorDec::isRight(QString s) {
return (s == ")");
}
int QCalculatorDec::priority(QString s) {
int ret = 0;
if ((s == '+') || (s == '-')) {
ret = 1;
}
if ((s == '*') || (s == '/')) {
ret = 2;
}
return ret;
}
bool QCalculatorDec::match(QQueue<QString> &exp) {
bool ret = true;
QStack<QString> s;
for (int i = 0; i < exp.length(); i++) {
if (isLeft(exp[i])) {
s.push(exp[i]);
}
else if (isRight(exp[i])) {
if (!s.isEmpty() && isLeft(s.top())) {
s.pop();
}
else {
ret = false;
break;
}
}
}
return ret;
}
QString QCalculatorDec::calculate(QQueue<QString> &exp) {
QString ret = "Error";
QStack<QString> s;
while (!exp.isEmpty()) {
QString e = exp.dequeue();
if (isNumber(e)) {
s.push(e);
}
else if (isOperator(e)) {
QString right = !s.isEmpty() ? s.pop() : "";
QString left = !s.isEmpty() ? s.pop() : "";
QString result = calculate(left, e, right);
if (result != "Error") {
s.push(result);
}
else {
break;
}
}
else {
break;
}
}
if (exp.isEmpty() && s.size() == 1 && isNumber(s.top())) {
ret = s.pop();
}
return ret;
}
QString QCalculatorDec::calculate(const QString &l, const QString &op, const QString &r) {
QString ret = "Error";
if (isNumber(l) && isNumber(r) && isOperator(op)) {
double ld = l.toDouble();
double rd = r.toDouble();
if (op == "+") {
ret.sprintf("%f", ld + rd);
}
else if (op == "-") {
ret.sprintf("%f", ld - rd);
}
else if (op == "*") {
ret.sprintf("%f", ld * rd);
}
else if (op == "/") {
const double P = 0.00000000000000001;
if ((-P < rd) && (rd < P)) {
ret = "Error";
}
else {
ret.sprintf("%f", ld / rd);
}
}
}
return ret;
}
bool QCalculatorDec::transform(QQueue<QString> &exp, QQueue<QString> &output) {
bool ret = match(exp);
QStack<QString> s;
output.clear();
while (!exp.isEmpty()) {
QString e = exp.dequeue();
if (isNumber(e)) {
output.enqueue(e);
}
else if (isOperator(e)) {
while (!s.isEmpty() && priority(e) <= priority(s.top())) {
output.enqueue(s.pop());
}
s.push(e);
}
else if (isLeft(e)) {
s.push(e);
}
else if (isRight(e)) {
while (!s.isEmpty() && !isLeft(s.top())) {
output.enqueue(s.pop());
}
if (!s.isEmpty()) {
s.pop();
}
} else {
ret = false;
}
}
while (!s.isEmpty()) {
output.enqueue(s.pop());
}
if (!ret) {
output.clear();
}
return ret;
}
QQueue<QString> QCalculatorDec::split(const QString &exp) {
QString num = "";
QString pre = "";
QQueue<QString> ret;
for (int i = 0; i < exp.length(); i++) {
if (isDigitOrDot(exp[i])) {
num += exp[i];
pre = exp[i];
}
else if (isSymbol(exp[i])) {
if (num != "") {
ret.enqueue(num);
num.clear();
}
if (isSign(exp[i]) && ((pre == "") || (isLeft(pre)) || (isOperator(pre)))) {
num += exp[i];
}
else {
ret.enqueue(exp[i]);
}
pre = exp[i];
}
}
if (!num.isEmpty()) {
ret.enqueue(num);
}
return ret;
}
bool QCalculatorDec::isOperator(QString s) {
return (s == '+') || (s == '-') || (s == '*') || (s == '/');
}
QCalculatorDec::QCalculatorDec() {
}
bool QCalculatorDec::expression(const QString &exp) {
bool ret = false;
QQueue<QString> spExp = split(exp);
QQueue<QString> postExp;
if (transform(spExp, postExp)) {
m_result = calculate(postExp);
ret = (m_result != "Error");
}
else {
m_result = "Error";
}
return ret;
}
QString QCalculatorDec::result() {
return m_result;
}
/* QCalculator.h */
#ifndef QCALCULATOR_H
#define QCALCULATOR_H
#include "QCalculatorUI.h"
#include "QCalculatorDec.h"
class QCalculator
{
protected:
QCalculatorUI* m_ui;
QCalculatorDec m_cal;
QCalculator();
bool construct();
public:
static QCalculator* NewInstance();
void show();
~QCalculator();
};
#endif // QCALCULATOR_H
/* QCalculatorl.cpp */
#include "QCalculator.h"
QCalculator::QCalculator() {
}
bool QCalculator::construct() {
m_ui = QCalculatorUI::NewInstance();
if (m_ui != NULL) {
m_ui->setCalculator(&m_cal);
}
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;
}
/* main.cpp*/
#include <QWidget>
#include <QApplication>
#include "QCalculator.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCalculator* cal = QCalculator::NewInstance();
int ret = -1;
if (cal != NULL) {
cal->show();
ret = a.exec();
delete cal;
}
return ret;
}