【问题标题】:How to decouple in this case在这种情况下如何解耦
【发布时间】:2012-11-27 10:57:30
【问题描述】:

例如,下面的 sn -p 做这些事情:首先从数据库中读取数据,然后转换数据,最后将结果写回数据库。更具体地说:

  1. 从数据库中读取数据并逐条记录存储到A类中。
  2. 逐条转换存储在 A 类中的数据,B 类完成这项工作。
  3. 将所有结果存储在 QVariantList 中并批量写入 ihe 数据库。

问题是 A 类、B 类和 ReadTransWrite 类之间的紧密耦合 如果我想将成员变量 A4 添加到类 A 中,需要更改 3 个类。 查看以“//-->”开头的评论

如何解耦?有什么模式可以推荐吗?有什么建议吗?

片段:

class A {
public: 
    void trans(QSqlQuery query){
        A1 = query.record().field("A1").value().toString();
        A2 = query.record().field("A2").value().toDate();
        A3 = query.record().field("A3").value().toInt();
        //--> A4 = query.record().field("A4").value().toDouble();
    }
public:
    QString A1;
    QDate A2;
    int A3;
    //--> double A4;
};

class B {
public:
    void trans(const A& a){
        B1 = A1;
        B2 = A2;
        B3 = A3;
        //--> B4 = A4;
    }
public:
    QString B1;
    QDate B2;
    int B3;
    //--> double B4;
};

class ReadTransWrite {
.....
    void do();
.....
}

void ReadTransWrite::do(){
    ....
    // prepare for batch insert into the database
    QVariantList B1s;
    QVariantList B2s;
    QVariantList B3s;
    //--> QVariantList B4s;

    A a;  // read record by record from data base
    B b;  // transform the results record by record

    QString sql_read = "select A1, A2, A3 from table0";
    //--> QString sql_read = "select A1, A2, A3, A4 from table0";
    QSqlQuery query_read;
    query_read.exec(sql_read);
    while(query_read.next()){
        a.trans(query_read);    // read record by record from data base
        b.trans(a);             // transform the results record by record
        B1s.push_back(b.B1);
        B2s.push_back(b.B2);
        B3s.push_back(b.B3);
        //--> B4s.push_back(b.B4);
    }

    QSqlQuery query_write;
    QString sql_write = "insert into table (B1, B2, B3) values (:B1, :B2, :B3)";
    //--> QString sql_write = "insert into table (B1, B2, B3, B4) values (:B1, :B2, :B3, :B4)";
    query_write.prepare(sql_write);

    query_write.bindValue(":B1",B1s);
    query_write.bindValue(":B2",B2s);
    query_write.bindValue(":B3",B3s);
    //--> query_write.bindValue(":B4",B4s);

    query_write.execBatch();
}

【问题讨论】:

  • A1 = query.record().field("A1").value().toString(); -- srsly? Law Of Demeter
  • 如果“数据库”、“表”和“字段”之类的东西是您应用程序中的业务对象,那么这些东西几乎是不可避免的。如果您的业务对象更像“客户”、“供应商”和“订单”,并且数据库严格来说是它们的持久性机制,那么很可能class Customer 之外的任何人都不会或需要查看与客户相关的表或字段数据类型。只是一个想法。
  • @sehe 请原谅我对“得墨忒耳法则”的无知,感谢蒂姆的提醒。是的,很好
  • 不幸的是,我觉得它看起来更像第一个案例,但你提到的第二个案例很有帮助,谢谢@n.m.

标签: c++ qt decouple


【解决方案1】:

你可以这样制作 A 类:

#include <QtCore/QVariant>
#include <QtSql/QSqlRecord>

class A 
{
public: 
    void fillFromRecord( const QSqlRecord& record )
    {
        for( int iColumn = 0; iColumn < record.count(); iColumn++ )
        {
            _contentMap.insert( 
                record.fieldName( iColumn ), 
                record.value( iColumn )
                );
        }
    }

    inline QVariantMap getContentMap() const { return _contentMap; }

private:
    QVariantMap _contentMap;
};

注意:我没有测试该代码的编译错误,但它至少应该给你一个大致的概念。


这样,每当数据库发生变化时,A 类就不会发生变化。

另请注意,您如何只要求QSqlRecord 而不是QSqlQuery 以更多地致力于sehe 在评论中链接的得墨忒耳法则。

您可以根据需要更改映射的类型,例如 QHash 仅存储列索引而不是名称并且不需要额外的 QMap 功能(基本上是排序)可能就足够了好吧。

【讨论】:

  • 很好的建议,我会努力改进我的情况,并在这里发布。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-10-19
  • 2021-08-24
  • 2016-04-24
  • 2017-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多