zoukankan      html  css  js  c++  java
  • 第十五课、用户界面与业务逻辑的分离------------------狄泰软件学院

    一、界面与逻辑

    1、基本程序框架一般包括

    (1)、用户界面模块(UI)

    A、接受用户输入及呈现数据

    (2)、业务逻辑模块

    A、根据用户需要处理数据

    二、基本设计原则

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

    2、核心思想:强内聚,弱耦合

    (1)、每个模块应该只实现单一的功能

    (2)、模块内部的子模块只为整体的单一功能而存在

    (3)、模块之间通过约定好的接口进行交互

    3、工程开发中的接口

    (1)、广义

    A、接口是一种契约(协议、语法、格式等)

    (2)、狭义

    A、面向过程:接口是一种预定义的函数模型

    B、面向对象:接口是纯虚类(c#和Java直接支持接口)

    4、用户界面和业务逻辑交互

    5、原则

    (1)、模块之间仅通过接口进行关联

    A、必然存在模块会使用接口

    B、必然存在模块实现对应接口

    (2)、模块间的关系是单项依赖的

    A、避免模块间存在循环依赖的情况

    B、循环依赖是糟糕的设计标准之一

    6、计算器应用程序的整体框架

    (1)、定义接口类:实现接收用户输入和返回计算结果

    (2)、界面模块使用接口

    (3)、计算模块实现接口的具体功能

    (4)、定义一个类将界面模块和计算模块结合起来

    #ifndef _QCALCULATORUI_H_
    #define _QCALCULATORUI_H_
    
    #include <QtGui/QApplication>
    #include <QLineEdit>
    #include <QPushButton>
    #include "ICalculator.h"
    
    class QCalculatorUI : public QWidget//继承自Qwid,可知。QCalculatorUI是QObject的间接子类
    {
        Q_OBJECT    //类声明最开始处使用Q_Object关键字
        QLineEdit* m_edit;//组合关系
        QPushButton* m_buttons[20];
    
        ICalculator* m_cal;//使用接口
    
        QCalculatorUI();
        bool construct();
    
    private slots://slots关键字
        void onButtonClicked();//与消息的函数签名一样,消息的clicked()没有参数,所以这里也没有
    
    public:
        static QCalculatorUI* NewInstance();
        void show();
        void setCalculator(ICalculator* cal);
        ICalculator* getCalculator();
    
        ~QCalculatorUI();
    };
    
    #endif // _QCALCULATORUI_H_
    QCalculatorUI.h
    #include "QCalculatorUI.h"
    
    QCalculatorUI::QCalculatorUI()  : QWidget(NULL,Qt::WindowCloseButtonHint )
    {
        m_cal = NULL;
    }
    
    bool QCalculatorUI::construct()
    {
    
        bool ret = true;
        m_edit = new QLineEdit(this);//父组件是this的原因:组合关系,同生死共存亡
        const char* btnText[20] =
        {
            "7", "8", "9", "+", "(",
            "4", "5", "6", "-", ")",
            "1", "2", "3", "*", "<-",
            "0", ".", "=", "/", "C"
        };
    
        if(m_edit != NULL)
        {
            m_edit->resize(240,30);
            m_edit->move(10,10);
            m_edit->setReadOnly(true);//设置文本框为只读,不输入字符串
            m_edit->setAlignment(Qt::AlignRight);//设置向右对齐
    
        }
        else
        {
            ret = false;
        }
    
        for(int i=0; (i<4) && ret; i++)//(i<4) && ret表示QLineEdit没有生成,这里也 没必要运行了
        {
            for(int j=0; (j<5) && ret; j++)
            {
                m_buttons[i*5 + j] = new QPushButton(this);
                if(m_buttons[i*5 + j])
                {
                    m_buttons[i*5 + j] ->resize(40,40);//[i*5 + j]是转换为一维来算
                    m_buttons[i*5 + j]->move(10 + (10 + 40)*j, 50 + (10 + 40)*i);//横坐标移五个,纵坐标移四个
                    m_buttons[i*5 + j]->setText(btnText[i*5 + j]);
                    connect(m_buttons[i*5 + j], SIGNAL(clicked()), this, SLOT(onButtonClicked()));//将信号映射到当前对象的onButtonclick()
                }
                else
                {
                    ret = false;
                }
    
            }
        }
    
        return ret;
    
    }
    QCalculatorUI* QCalculatorUI::NewInstance()
    {
        QCalculatorUI* ret = new QCalculatorUI();
    
        if(!(ret && ret->construct()))
        {
            delete ret;
            ret = NULL;
        }
    
        return ret;
    }
    void QCalculatorUI::show()
    {
        QWidget::show();
        setFixedSize(width(), height());//要放在show()后,否则是先固定再显示
    }
    
    void QCalculatorUI::onButtonClicked()
    {
        QPushButton* btn = dynamic_cast<QPushButton*>(sender());//返回一个指向发送信号的对象的指针
    
        if(btn != NULL)
        {
            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);
            }
    
        }
    }
    
    void QCalculatorUI::setCalculator(ICalculator* cal)
    {
        m_cal = cal;
    }
    ICalculator* QCalculatorUI::getCalculator()
    {
        return m_cal;
    }
    
    QCalculatorUI::~QCalculatorUI()
    {
    
    }
    QCalculatorUI.cpp
    #ifndef QCalculatorDec_H
    #define QCalculatorDec_H
    
    #include<QQueue>
    #include <QString>
    #include <QStack>
    #include "ICalculator.h"
    
    class QCalculatorDec : public ICalculator //继承接口类并实现具体功能
    {
    protected:
        QString m_exp;
        QString m_result;
        //分离算法
        bool isDigitOrDot(QChar c);//数字和.
        bool isSymbol(QChar c);//字符
        bool isSign(QChar c);//符合+-
        bool isOperator(QString s);//参数为Qstring 的原因是后面要将pre作为参数传入
        QQueue<QString> split(const QString& exp);//将分离后的结果保存到队列中
    
        //中缀转后缀
        bool isNumber(QString s);
        bool isLeft(QString s);
        bool isRight(QString s);
        int priority(QString s);
        bool match(QQueue<QString>& exp);
        bool transform(QQueue<QString>& exp, QQueue<QString>& output);
    
        //计算结果
        QString calculator(QString lp, QString op, QString rp);
        QString calculator(QQueue<QString>& exp);
    
    public:
        //计算结果
        bool expression(const QString& exp);//实现接口的功能
        QString result();
    
        QCalculatorDec();
        ~QCalculatorDec();
    };
    
    #endif // QCalculatorDec_H
    QCalculatorDec.h
    #include "QCalculatorDec.h"
    #include <QDebug>
    
    QCalculatorDec::QCalculatorDec()
    {
        m_exp = "";
        m_result = "";
    }
    //1.分离算法
    
    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::isOperator(QString s)
    {
        return (s == "+") || (s == "-") || (s == "*") || (s == "/");
    }
    
    QQueue<QString> QCalculatorDec::split(const QString& exp)
    {
        QQueue<QString> ret;
        QString num = "";
        QString pre = "";
        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.isEmpty())
                {
                    ret.enqueue(num);
                    num.clear();
                }
    
                if(isSign(exp[i]) && ((pre == "") || (pre == "(") || (isOperator(pre))))
                {
                    num += exp[i];
                }
                else
                {
                    ret.enqueue(exp[i]);
                }
                pre = exp[i];
    
            }
        }
    
        if(! num.isEmpty())
        {
            ret.enqueue(num);
        }
        return ret;
    }
    
    
    
    
    
    //2.中缀转后缀
    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;//这里设定括号的优先级为0
        if(s == "+" || s == "-")
        {
            ret = 1;
        }
        if(s == "*" || s == "/")
        {
            ret = 2;
        }
        return ret;
    }
    bool QCalculatorDec::match(QQueue<QString>& exp)
    {
        bool ret = true;
        QStack<QString> statck;
    
        for(int i=0; i<exp.length(); i++)
        {
            if(isLeft(exp[i]))//1.是左括号就直接入栈
            {
                statck.push(exp[i]);
            }
            else if(isRight(exp[i]))//2.由括号就判断栈顶元素是不是左括号,是就弹出不要
            {
                if(!statck.isEmpty() && isLeft(statck.top()))
                {
                    statck.pop();
                }
                else
                {
                    ret = false;
                    break;//如果有出错也就没必要往下继续判断了
                }
            }
    
        }
    
        return ret && statck.isEmpty();
    }
    bool QCalculatorDec::transform(QQueue<QString>& exp, QQueue<QString>& output)
    {
        bool ret = match(exp);
        QStack<QString> statck;
        output.clear();
    
        while(ret && !exp.isEmpty())
        {
            QString e = exp.dequeue();
            if(isNumber(e))//1.是数字直接输出
            {
                output.enqueue(e);
            }
            else if(isOperator(e))//2.是操作符先判断优先级
            {
                while(!statck.isEmpty() && (priority(e) <= priority(statck.top())))
                {
                    output.enqueue(statck.pop());
                }
    
                statck.push(e);
    
            }
            else if(isLeft(e))//3.是左括号直接入栈
            {
                statck.push(e);
            }
            else if(isRight(e))//4.是右括号就把栈元素输出直至遇到左括号
            {
                if(!statck.isEmpty() && (!isLeft(statck.top())))
                {
                    output.enqueue(statck.pop());
                }
                if(!statck.isEmpty())
                {
                    statck.pop();
                }
    
            }
            else
            {
                ret = false;
            }
        }
    
        while (!statck.isEmpty())//5.将栈里剩余的元素全部输出
        {
            output.enqueue(statck.pop());
        }
        if(!ret)
        {
            output.clear();
        }
    
        return ret;
    }
    
    //计算结果
    QString QCalculatorDec::calculator(QString lp, QString op, QString rp)
    {
        QString ret = "Error";
        if(isNumber(lp) && isNumber(rp))
        {
            double l = lp.toDouble();
            double r = rp.toDouble();
    
            if(op == "+")
            {
                ret.sprintf("%f", l + r);
            }
            else if(op == "-")
            {
                ret.sprintf("%f", l - r);
            }
            else if(op == "*")
            {
                ret.sprintf("%f", l * r);
            }
            else if(op == "/")
            {
                const double p = 0.00000000000001;
                if((-p < r) && (r < p))
                {
                    ret = "Error";
                }
                else
                {
                    ret.sprintf("%f", l / r);
                }
            }
            else
            {
                ret = "Error";
            }
        }
        return ret;
    }
    QString QCalculatorDec::calculator(QQueue<QString>& exp)
    {
        QString ret = "Error";
        QStack<QString> statck;
    
        while(!exp.isEmpty())
        {
            QString e = exp.dequeue();
    
            if( isNumber(e) )//1.若是数字,进栈
            {
                statck.push(e);
            }
            else if( isOperator(e) )//2.是操作符,弹出右操作数,弹出左操作数,将结果入栈
            {
                if( !statck.isEmpty() )
                {
                    QString rp = statck.pop();
                    QString lp = statck.pop();
    
                    QString result = calculator(lp, e, rp);
    
                    if(result != "Error")
                    {
                        statck.push(result);
                    }
                    else
                    {
                        break;
                    }
                }
            }
            else//3.else表达式错误
            {
                break;
            }
        }
        if(!statck.isEmpty() && statck.size() == 1 && isNumber(statck.top()))
        {
            ret = statck.pop();
        }
        return ret;
    }
    bool QCalculatorDec::expression(const QString& exp)
    {
        bool ret = false;
        QQueue<QString> spExp = split(exp);
        QQueue<QString> posExp;
    
        m_exp = exp;
    
        if(transform(spExp, posExp))
        {
            m_result = calculator(posExp);
    
            ret = (m_result != "Error");
        }
        else
        {
            m_result = "Error";
        }
    
        return ret;
    }
    QString QCalculatorDec::result()
    {
        return m_result;
    }
    QCalculatorDec::~QCalculatorDec()
    {
        
    }
    QCalculatorDec.cpp
    #ifndef QCalculator_H
    #define QCalculator_H
    #include "QCalculatorDec.h"
    #include "QCalculatorUI.h"
    
    //实现界面类与计算逻辑类的关联
    class QCalculator
    {
    protected:
        QCalculatorUI* m_ui;//用指针的原因是它使用二阶构造
        QCalculatorDec m_cal;
        QCalculator();
        bool construct();
    
    public:
        static QCalculator* NewInstance();//成员有二阶构造,使用它的类也要二阶构造
        void show();
        ~QCalculator();
    };
    
    #endif // QCalculator_H
    QCalculator.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;
    }
    QCalculator.cpp
    #ifndef ICALCULATOR_H
    #define ICALCULATOR_H
    #include <QString>
    
    //定义接口类
    //1.提供一个接收输入的接口
    //2.提供一个输出结果的接口
    //单依赖:接口的具体功能由核心算法类实现,接口由界面文件使用
    class ICalculator
    {
    public:
        virtual bool expression(const QString& exp) = 0;
        virtual QString result() = 0;
    };
    
    #endif // ICALCULATOR_H
    ICalculator.h
    #include <QtGui/QApplication>
    #include "QCalculator.h"
    
    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;
    
    }
    main.cpp

    二、小结

    (1)、模块直接的交互需要通过接口来完成

    (2)、接口是开发中模块之间的一种契约

    (3)、模块之间不能出现循环依赖

    (4)、基本设计原则:强内聚,弱耦合

  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/gui-lin/p/6398435.html
Copyright © 2011-2022 走看看