《重构:改善既有代码的设计》 重新组织数据 之 6

版权声明:请注明转发出处 https://blog.csdn.net/mafucun1988/article/details/89630990

《重构:改善既有代码的设计》中提到过很多重构方法,关于重新组织数据的方法有8种。本文介绍:
复制“被监控数据” dumplicate Observed Data

  • 名称:复制“被监控数据” dumplicate Observed Data
  • 概要:有一些领域数据置身于GUI控件中,而领域函数需要访问这些数据
  • 动机: 分层良好的系统,应该将处理用户界面和处理业务逻辑的代码分开。好处是 
    • 使用不同的用户界面表现相同的业务逻辑
    • 隔离后,不同的开发者开发不同部分的开发

  • 做法:
    • 修改展现类(GUI),使其成为领域类的observer。如果没有领域类,就建立一个。如果没有“从展现类到领域类”的关联,就将领域类保存于展现类的一个字段中
    • 针对GUI类中的领域数据,使用self encapsulate field, 在事件处理函数中调用设值函数,直接更新GUI组件。
    • 编译,测试
    • 在领域类中定义数据及其相关访问函数。确保领域类中的设值函数能够触发Observer模式的通报机制。对于被观察的数据,在领域类中使用与展现类所用的相同类型(通常是字符串)来保存。
    • 修改展现类中的访问函数,将他们的操作对象改为领域对象(而非GUI组件)
    • 修改Observer的Update(),使其从相应的领域对象中将所需数据复制给GUI组件。
    • 编译,测试
  • 代码演示

修改之前的代码:

////////////////////////.h
class MainWindowTest : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindowTest(QWidget *parent = nullptr);
    ~MainWindowTest();


private slots:
    void slot_LineEditStartEditingFinished();
    void slot_LineEditEndEditingFinished();
    void slot_LineEditLengthEditingFinished();

private:
    Ui::MainWindowTest *ui;
    Interval *m_pInterval;
};

////////////////////////.cpp
#include "MainWindowTest.h"
#include "ui_MainWindowTest.h"

MainWindowTest::MainWindowTest(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindowTest)
{
    m_pInterval = Interval::getInstance();
    ui->setupUi(this);
    setStart(m_pInterval->getStart());
    setEnd(m_pInterval->getEnd());
    setLength(m_pInterval->getLength());
    connect(ui->lineEdit_Start, SIGNAL(editingFinished()), this, SLOT(slot_LineEditStartEditingFinished()));
    connect(ui->lineEdit_End, SIGNAL(editingFinished()), this, SLOT(slot_LineEditEndEditingFinished()));
    connect(ui->lineEdit_Length, SIGNAL(editingFinished()), this, SLOT(slot_LineEditLengthEditingFinished()));
}

MainWindowTest::~MainWindowTest()
{
    delete ui;
}

Interval* Interval::m_pInterval = nullptr;
Interval::Interval():m_Start(0), m_End(0),m_Length(0)
{

}

Interval *Interval::getInstance()
{
    if (nullptr == m_pInterval)
    {
        m_pInterval =  new Interval();
    }
    return m_pInterval;
}

void Interval::calculateLength()
{
    setLength( m_End - m_Start);
}

void Interval::calculateEnd()
{
    setEnd( m_Start + m_Length);
}

void MainWindowTest::Update()
{
    m_pInterval->setStart(ui->lineEdit_Start->text().toDouble());
    m_pInterval->setEnd(ui->lineEdit_End->text().toDouble());
    m_pInterval->setLength(ui->lineEdit_Length->text().toDouble());
}

void MainWindowTest::slot_LineEditStartEditingFinished()
{
    Update();
    m_pInterval->calculateLength();
    setLength(m_pInterval->getLength());
}

//void MainWindowTest::on_lineEdit_Start_editingFinished()
//{

//}

void MainWindowTest::on_lineEdit_Test_editingFinished()
{
    ui->lineEdit_Test->setText(ui->lineEdit_Test->text()+"*");
}

void MainWindowTest::slot_LineEditEndEditingFinished()
{
    Update();
    m_pInterval->calculateLength();
    setLength(m_pInterval->getLength());
}

void MainWindowTest::slot_LineEditLengthEditingFinished()
{
    Update();
    m_pInterval->calculateEnd();
    setEnd(m_pInterval->getEnd());
}

double MainWindowTest::getStart() const
{
    return ui->lineEdit_Start->text().toDouble();
}

void MainWindowTest::setStart(double Start)
{
    ui->lineEdit_Start->setText(QString("%1").arg(Start));
}

double MainWindowTest::getEnd() const
{
    return ui->lineEdit_End->text().toDouble();
}

void MainWindowTest::setEnd(double End)
{
    ui->lineEdit_End->setText(QString("%1").arg(End));
}

double MainWindowTest::getLength() const
{
    return ui->lineEdit_Length->text().toDouble();
}

void MainWindowTest::setLength(double Length)
{
    ui->lineEdit_Length->setText(QString("%1").arg(Length));
}

double Interval::getStart() const
{
    return m_Start;
}

void Interval::setStart(double Start)
{
    m_Start = Start;
    notify();
}

double Interval::getEnd() const
{
    return m_End;
}

void Interval::setEnd(double End)
{
    m_End = End;
    notify();
}

double Interval::getLength() const
{
    return m_Length;
}

void Interval::setLength(double Length)
{
    m_Length = Length;
    notify();
}

void Interval::notify()
{
    for (MainWindowTest *pWindow : m_pWindowList)
    {
        pWindow->setStart(m_Start);
        pWindow->setEnd(m_End);
        pWindow->setLength(m_Length);
    }
}

运行后:

修改之后的代码:
1) 创建领域类interval
2)对start,end,length三个变量使用使用self encapsulate field
3) 在领域类中定义数据及其相关访问函数,将calculateLength()和calculateEnd()移到领域类,当数据变化时触发notify()
4) 修改展现类MainwindowTest中的访问函数,将他们的操作对象改为领域对象Interval
5)修改Observer的Update(),使其从相应的领域对象中将所需数据复制给GUI组件。

/////////////////////////.h
#ifndef MAINWINDOWTEST_H
#define MAINWINDOWTEST_H

#include <QMainWindow>
#include <QList>

namespace Ui {
class MainWindowTest;
}
class MainWindowTest;
class Interval
{
public:
    Interval();
    static Interval* getInstance();
    void calculateLength();
    void calculateEnd();

    double getStart() const;
    void setStart(double Start);
    double getEnd() const;
    void setEnd(double End);
    double getLength() const;
    void setLength(double Lenght);
    void notify();
private:
    double m_Start;
    double m_End;
    double m_Length;
    QList<MainWindowTest *> m_pWindowList;
    static Interval* m_pInterval;
};


class MainWindowTest : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindowTest(QWidget *parent = nullptr);
    ~MainWindowTest();

    void Update();

    double getStart() const;
    void setStart(double Start);
    double getEnd() const;
    void setEnd(double End);
    double getLength() const;
    void setLength(double Length);

private slots:
    //    void on_lineEdit_Start_editingFinished();
    void on_lineEdit_Test_editingFinished();
    void slot_LineEditStartEditingFinished();
    void slot_LineEditEndEditingFinished();
    void slot_LineEditLengthEditingFinished();

private:
    Ui::MainWindowTest *ui;
    Interval *m_pInterval;

};

#endif // MAINWINDOWTEST_H

//////////////////////////.cpp
#include "MainWindowTest.h"
#include "ui_MainWindowTest.h"

MainWindowTest::MainWindowTest(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindowTest)
{
    m_pInterval = Interval::getInstance();
    ui->setupUi(this);
    ui->lineEdit_Start->setText("0");
    ui->lineEdit_End->setText("0");
    ui->lineEdit_Length->setText("0");
    connect(ui->lineEdit_Start, SIGNAL(editingFinished()), this, SLOT(slot_LineEditStartEditingFinished()));
    connect(ui->lineEdit_End, SIGNAL(editingFinished()), this, SLOT(slot_LineEditEndEditingFinished()));
    connect(ui->lineEdit_Length, SIGNAL(editingFinished()), this, SLOT(slot_LineEditLengthEditingFinished()));
}

MainWindowTest::~MainWindowTest()
{
    delete ui;
}

Interval* Interval::m_pInterval = nullptr;
Interval::Interval()
{

}

Interval *Interval::getInstance()
{
    if (nullptr == m_pInterval)
    {
        m_pInterval =  new Interval();
    }
    return m_pInterval;
}

void Interval::calculateLength()
{
    setLength( m_End - m_Start);
}

void Interval::calculateEnd()
{
    setEnd( m_Start + m_Length);
}

void MainWindowTest::Update()
{
    m_pInterval->setStart(ui->lineEdit_Start->text().toDouble());
    m_pInterval->setEnd(ui->lineEdit_End->text().toDouble());
    m_pInterval->setLength(ui->lineEdit_Length->text().toDouble());
}

void MainWindowTest::slot_LineEditStartEditingFinished()
{
    Update();
    m_pInterval->calculateLength();
    setLength(m_pInterval->getLength());
}

//void MainWindowTest::on_lineEdit_Start_editingFinished()
//{

//}

void MainWindowTest::on_lineEdit_Test_editingFinished()
{
    ui->lineEdit_Test->setText(ui->lineEdit_Test->text()+"*");
}

void MainWindowTest::slot_LineEditEndEditingFinished()
{
    Update();
    m_pInterval->calculateLength();
    setLength(m_pInterval->getLength());
}

void MainWindowTest::slot_LineEditLengthEditingFinished()
{
    Update();
    m_pInterval->calculateEnd();
    setEnd(m_pInterval->getEnd());
}

double MainWindowTest::getStart() const
{
    return ui->lineEdit_Start->text().toDouble();
}

void MainWindowTest::setStart(double Start)
{
    ui->lineEdit_Start->setText(QString("%1").arg(Start));
}

double MainWindowTest::getEnd() const
{
    return ui->lineEdit_End->text().toDouble();
}

void MainWindowTest::setEnd(double End)
{
    ui->lineEdit_End->setText(QString("%1").arg(End));
}

double MainWindowTest::getLength() const
{
    return ui->lineEdit_Length->text().toDouble();
}

void MainWindowTest::setLength(double Length)
{
    ui->lineEdit_Length->setText(QString("%1").arg(Length));
}

double Interval::getStart() const
{
    return m_Start;
}

void Interval::setStart(double Start)
{
    m_Start = Start;
    notify();
}

double Interval::getEnd() const
{
    return m_End;
}

void Interval::setEnd(double End)
{
    m_End = End;
    notify();
}

double Interval::getLength() const
{
    return m_Length;
}

void Interval::setLength(double Length)
{
    m_Length = Length;
    notify();
}

void Interval::notify()
{
    for (MainWindowTest *pWindow : m_pWindowList)
    {
        pWindow->setStart(m_Start);
        pWindow->setEnd(m_End);
        pWindow->setLength(m_Length);
    }
}

猜你喜欢

转载自blog.csdn.net/mafucun1988/article/details/89630990