• Qt学习15 用户界面与业务逻辑的分离


    Qt学习15 用户界面与业务逻辑的分离

    界面与逻辑

    • 基本程序架构一般包含:
      • 用户界面模块 (UI)
        • 接受用户输入及呈现数据
      • 业务逻辑模块 (Business Logic)
        • 根据用户需求处理数据

    问题

    用户界面业务逻辑如何交互

    基本设计原则

    • 功能模块之间需要进行解耦

    • 核心思想:高内聚,低耦合

      • 每个模块应该只实现单一的功能
      • 模块内部的子模块只为整体的单一功能而存在
      • 模块之间通过约定好的接口进行交互
    • 在工程开发中接口是什么

      • 广义:
        • 接口是一种契约(协议,语法,格式等)
      • 狭义:
        • 面向过程:接口是一组预定义的函数原型
        • 面向对象:接口是纯虚类(C#和Java直接支持接口)
    • 用户界面与业务逻辑的交互

    在这里插入图片描述

    • 模块之间仅通过接口进行关联

      • 必然存在模块回使用接口
      • 必然存在模块实现对应的接口
    • 模块间的关系是单项依赖

      • 避免模块间存在循环依赖的情况
      • 循环依赖是糟糕设计的标准之一
    • 计算器应用程序的整体架构

    在这里插入图片描述

    代码展示

    ICalculator.h

    /* 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    QCalculatorUI.h

    /* 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    QCalculatorUI.cpp

    /* 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);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

    QCalculatorDec.h

    /* 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    QCalculatorDec.cpp

    /* 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211

    QCalculator.h

    /* 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    QCalculatorl.cpp

    /* 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    main.cpp

    /* 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    小结

    • 模块之间的交互需要通过接口完成
    • 接口是开发中模块之间的一种**“契约”**
    • 模块之间不能出现循环依赖
    • 基本设计原则:高内聚,低耦合
  • 相关阅读:
    opencascade 布尔运算笔记
    MongoDB的管理与监控
    30天拿下Rust之前世今生
    uniapp之使用map组件显示接收过来的经纬度
    Android Apk一键打包上传至蒲公英平台的gradle脚本
    【RPA实战】 中秋节月饼不知道买哪种?UiPath零代码2分钟获取1000种月饼商品信息告诉你答案
    jenkins(pipeline)+k8s 实现CICD(提供源码和测试用例)
    使用scala语言编写代码,一键把hive中的DDLsql转化成MySql中的DDLsql
    随手记录第六话 -- 在Mac上搭建整个开发环境记录(Java、Python、Vue、Docker、idea)
    云厂商 RDS MySQL 怎么选
  • 原文地址:https://blog.csdn.net/weixin_40743639/article/details/125509130