[QT] QTはデータのカプセル化によりJson構造とデータクラスの相互変換を実現します

開発プロジェクトで最も重要な部分はデータですが、ここでは QT プロジェクトにおけるデータのカプセル化方法を説明します。メソッド内でカプセル化されたデータは自己監視でき、変更後は積極的にメッセージを外部に送信して変更を通知すると同時に、カプセル化されたデータを JSON データ構造との間で変換することができます。これは、データの永続化とネットワーク リクエストに非常に役立ちます。

基本型のカプセル化

コードの再利用性を向上させるために、ここでは一般的なメソッドとプロパティを基本的なプロパティ タイプでカプセル化し、プログラムの呼び出しを容易にします。基本型間の継承関係を次の図に示します。

ここに画像の説明を挿入

DatabDecoratorデータ カプセル化の基本クラスであり、データ コンテンツのいくつかの共通属性が含まれています。
StringDecorator文字列型属性のカプセル化です。
IntDecorator整数型属性のカプセル化です。
EnumeratorDecorator列挙型データのカプセル化
DateTimeDecoratorです。日付型データ。

基本型のデータベースクラスは以下の通りで、属性フィールドに必要な追加の補助パラメータと、Json構造と相互変換するためのメソッドインターフェースをカプセル化します。

1、datadecorator.h

#ifndef DATADECORATOR_H
#define DATADECORATOR_H

#include <QJsonObject>
#include <QJsonValue>
#include <QObject>
#include <QScopedPointer>

class Entity;
class DataDecorator : public QObject
{
    
    
    Q_OBJECT
    //导出QML中需要访问属性
    Q_PROPERTY( QString ui_describe READ label CONSTANT )
public:
    /**@brief 构造描述
   * @1 该属性字段属于哪个数据实体
   * @2 该属性字段对应的key值
   * @3 该属性字段对应的描述信息
   */
    DataDecorator(Entity* parent = nullptr, const QString& key = "SomeItemKey", const QString& label = "");
    virtual ~DataDecorator();

    const QString& key() const;   //key值用来查找该属性
    const QString& label() const; //label用来描述该属性字段
    Entity* parentEntity();       //属性字段属于哪个数据实体(比如用户等)

    //Json和数据类之间的相互转化
    virtual QJsonValue jsonValue() const = 0;
    virtual void update(const QJsonObject& jsonObject) = 0;

private:
    //私有的数据类
    class Implementation;
    QScopedPointer<Implementation> implementation;
};
#endif

2、データデコレータ.cpp

#include "data-decorator.h"
class DataDecorator::Implementation
{
    
    
public:
    Implementation(Entity* _parent, const QString& _key, const QString& _label)
        : parentEntity(_parent)
        , key(_key)
        , label(_label)
    {
    
    
    }
    Entity* parentEntity{
    
    nullptr};
    QString key;
    QString label;
};

DataDecorator::DataDecorator(Entity* parent, const QString& key, const QString& label)
    : QObject((QObject*)parent)
{
    
    
    implementation.reset(new Implementation(parent, key, label));
}
DataDecorator::~DataDecorator()
{
    
    
}
const QString& DataDecorator::key() const
{
    
    
    return implementation->key;
}

const QString& DataDecorator::label() const
{
    
    
    return implementation->label;
}

Entity* DataDecorator::parentEntity()
{
    
    
    return implementation->parentEntity;
}

基本タイプのカプセル化クラスは DataDecorator クラスから派生し、次のように実装されます。

1.文字列型のカプセル化

1、stringdecorator.h

#ifndef STRINGDECORATOR_H
#define STRINGDECORATOR_H

#include <QJsonObject>
#include <QJsonValue>
#include <QObject>
#include <QScopedPointer>
#include <QString>
#include <data/data-decorator.h>

class  StringDecorator : public DataDecorator
{
    
    
    Q_OBJECT
   //QML访问的属性
    Q_PROPERTY( QString ui_value READ value WRITE setValue NOTIFY valueChanged )
public:
    StringDecorator(Entity* parentEntity = nullptr, const QString& key = "SomeItemKey", const QString& label = "", const QString& value = "");
    ~StringDecorator();

    //修改和获取字符串封装类型中的原始数据
    StringDecorator& setValue(const QString& value);
    const QString& value() const;

    QJsonValue jsonValue() const override;
    void update(const QJsonObject& jsonObject) override;

signals:
    //数据发生变化的时候发送的信号
    void valueChanged();

private:
    class Implementation;
    QScopedPointer<Implementation> implementation;
};

#endif

2、stringdecorator.cpp

#include "string-decorator.h"
#include <QVariant>

class StringDecorator::Implementation
{
    
    
public:
    Implementation(StringDecorator* _stringDecorator, const QString& _value)
        : stringDecorator(_stringDecorator)
        , value(_value)
    {
    
    
    }

    StringDecorator* stringDecorator{
    
    nullptr};
    QString value;
};

StringDecorator::StringDecorator(Entity* parentEntity, const QString& key, const QString& label, const QString& value)
    : DataDecorator(parentEntity, key, label)
{
    
    
    implementation.reset(new Implementation(this, value));
}

StringDecorator::~StringDecorator()
{
    
    
}

const QString& StringDecorator::value() const
{
    
    
    return implementation->value;
}

StringDecorator& StringDecorator::setValue(const QString& value)
{
    
    
    if(value != implementation->value) {
    
    
        implementation->value = value;
        emit valueChanged();
    }
    return *this;
}

QJsonValue StringDecorator::jsonValue() const
{
    
    
    return QJsonValue::fromVariant(QVariant(implementation->value));
}

void StringDecorator::update(const QJsonObject& _jsonObject)
{
    
    
    if (_jsonObject.contains(key())) {
    
    
        setValue(_jsonObject.value(key()).toString());
    }
}

2. 整数のカプセル化

1、intdecorator.h

#ifndef INTDECORATOR_H
#define INTDECORATOR_H

#include <QJsonObject>
#include <QJsonValue>
#include <QObject>
#include <QScopedPointer>
#include <data/data-decorator.h>

class  IntDecorator : public DataDecorator
{
    
    
    Q_OBJECT
   // QML访问的接口
    Q_PROPERTY( int ui_value READ value WRITE setValue NOTIFY valueChanged )

public:
    IntDecorator(Entity* parentEntity = nullptr, const QString& key = "SomeItemKey", const QString& label = "", int value = 0);
    ~IntDecorator();
 
    //修改和获取对应的属性值
    IntDecorator& setValue(int value);
    int value() const;

public:
    QJsonValue jsonValue() const override;
    void update(const QJsonObject& jsonObject) override;

signals:
    void valueChanged();

private:
    class Implementation;
    QScopedPointer<Implementation> implementation;
};

#endif

2、intdecorator.cpp

#include "int-decorator.h"
#include <QVariant>

class IntDecorator::Implementation
{
    
    
public:
    Implementation(IntDecorator* intDecorator, int value)
        : intDecorator(intDecorator)
        , value(value)
    {
    
    
    }

    IntDecorator* intDecorator{
    
    nullptr};
    int value;
};

IntDecorator::IntDecorator(Entity* parentEntity, const QString& key, const QString& label, int value)
    : DataDecorator(parentEntity, key, label)
{
    
    
    implementation.reset(new Implementation(this, value));
}

IntDecorator::~IntDecorator()
{
    
    
}

int IntDecorator::value() const
{
    
    
    return implementation->value;
}

IntDecorator& IntDecorator::setValue(int value)
{
    
    
    if(value != implementation->value) {
    
    
        // ...Validation here if required...
        implementation->value = value;
        emit valueChanged();
    }

    return *this;
}

QJsonValue IntDecorator::jsonValue() const
{
    
    
    return QJsonValue::fromVariant(QVariant(implementation->value));
}

void IntDecorator::update(const QJsonObject& jsonObject)
{
    
    
    if (jsonObject.contains(key())) {
    
    
        auto l_value = jsonObject.value(key()).toInt();
        setValue(l_value);
    } else {
    
    
        setValue(0);
    }
}

3. 列挙型をカプセル化する

他の基本型とは異なり、列挙型には整数値だけでなくマッピング テーブルも含まれており、各列挙値に対応する文字列マッピングがあり、列挙型の外部表示に使用されます。

1、列挙体デコレータ.h

#ifndef ENUMERATORDECORATOR_H
#define ENUMERATORDECORATOR_H
#include <map>
#include <QJsonObject>
#include <QJsonValue>
#include <QObject>
#include <QScopedPointer>
#include <data/data-decorator.h>

class EnumeratorDecorator : public DataDecorator
{
    
    
    Q_OBJECT
    //枚举属性值
    Q_PROPERTY( int ui_value READ value WRITE setValue NOTIFY valueChanged )
    //枚举属性对应的字符串描述
    Q_PROPERTY( QString ui_valueDescription READ valueDescription NOTIFY valueChanged )
public:
    EnumeratorDecorator(Entity* parentEntity = nullptr, const QString& key = "SomeItemKey", const QString& label = "", int value = 0, const std::map<int, QString>& descriptionMapper = std::map<int, QString>());
    ~EnumeratorDecorator();
   
    //获取属性对应的值和描述
    EnumeratorDecorator& setValue(int value);
    int value() const;
    QString valueDescription() const;

    QJsonValue jsonValue() const override;
    void update(const QJsonObject& jsonObject) override;

signals:
    void valueChanged();

private:
    class Implementation;
    QScopedPointer<Implementation> implementation;
};
#endif

2、列挙体デコレータ.cpp

#include "enumerator-decorator.h"
#include <QVariant>

class EnumeratorDecorator::Implementation
{
    
    
public:
    Implementation(EnumeratorDecorator* enumeratorDecorator, int value, const std::map<int, QString>& descriptionMapper)
        : enumeratorDecorator(enumeratorDecorator)
        , value(value)
        , descriptionMapper(descriptionMapper)
    {
    
    
    }

    EnumeratorDecorator* enumeratorDecorator{
    
    nullptr};
    int value;
    std::map<int, QString> descriptionMapper;
};

EnumeratorDecorator::EnumeratorDecorator(Entity* parentEntity, const QString& key, const QString& label, int value, const std::map<int, QString>& descriptionMapper)
    : DataDecorator(parentEntity, key, label)
{
    
    
    implementation.reset(new Implementation(this, value, descriptionMapper));
}

EnumeratorDecorator::~EnumeratorDecorator()
{
    
    
}

int EnumeratorDecorator::value() const
{
    
    
    return implementation->value;
}

QString EnumeratorDecorator::valueDescription() const
{
    
    
    if (implementation->descriptionMapper.find(implementation->value) != implementation->descriptionMapper.end()) {
    
    
        return implementation->descriptionMapper.at(implementation->value);
    } else {
    
    
        return {
    
    };
    }
}

EnumeratorDecorator& EnumeratorDecorator::setValue(int value)
{
    
    
    if (value != implementation->value) {
    
    
        // ...Validation here if required...
        implementation->value = value;
        emit valueChanged();
    }

    return *this;
}

QJsonValue EnumeratorDecorator::jsonValue() const
{
    
    
    return QJsonValue::fromVariant(QVariant(implementation->value));
}

void EnumeratorDecorator::update(const QJsonObject& jsonObject)
{
    
    
    if (jsonObject.contains(key())) {
    
    
        auto valueFromJson = jsonObject.value(key()).toInt();
        setValue(valueFromJson);
    } else {
    
    
        setValue(0);
    }
}

4. 日付型をカプセル化する

日付にはさまざまな表示形式があるため、呼び出し元が日付のさまざまな表示形式を取得できるように、日付カプセル化タイプのいくつかの新しいインターフェイスを拡張します。

1、日時デコレータ.h

#ifndef DATETIMEDECORATOR_H
#define DATETIMEDECORATOR_H

#include <QDateTime>
#include <QJsonObject>
#include <QJsonValue>
#include <QObject>
#include <QScopedPointer>
#include <data/data-decorator.h>

class DateTimeDecorator : public DataDecorator
{
    
    
    Q_OBJECT
    //QML中访问各种日期的格式
    Q_PROPERTY( QString ui_iso8601String READ toIso8601String NOTIFY valueChanged )
    Q_PROPERTY( QString ui_prettyDateString READ toPrettyDateString NOTIFY valueChanged )
    Q_PROPERTY( QString ui_prettyTimeString READ toPrettyTimeString NOTIFY valueChanged )
    Q_PROPERTY( QString ui_prettyString READ toPrettyString NOTIFY valueChanged )
    Q_PROPERTY( QDateTime ui_value READ value WRITE setValue NOTIFY valueChanged )

public:
    DateTimeDecorator(Entity* parentEntity = nullptr, const QString& key = "SomeItemKey", const QString& label = "", const QDateTime& value = QDateTime());
    ~DateTimeDecorator();

    const QDateTime& value() const;
    DateTimeDecorator& setValue(const QDateTime& value);

    //获取各种显示格式
    QString toIso8601String() const;
    QString toPrettyDateString() const;
    QString toPrettyTimeString() const;
    QString toPrettyString() const;

    QJsonValue jsonValue() const override;
    void update(const QJsonObject& jsonObject) override;

signals:
    void valueChanged();

private:
    class Implementation;
    QScopedPointer<Implementation> implementation;
};

#endif

2、日時デコレータ.cpp

#include "datetime-decorator.h"
#include <QVariant>

class DateTimeDecorator::Implementation
{
    
    
public:
    Implementation(DateTimeDecorator* dateTimeDecorator, const QDateTime& value)
        : dateTimeDecorator(dateTimeDecorator)
        , value(value)
    {
    
    
    }
    DateTimeDecorator* dateTimeDecorator{
    
    nullptr};
    QDateTime value;
};

DateTimeDecorator::DateTimeDecorator(Entity* parentEntity, const QString& key, const QString& label, const QDateTime& value)
    : DataDecorator(parentEntity, key, label)
{
    
    
    implementation.reset(new Implementation(this, value));
}

DateTimeDecorator::~DateTimeDecorator()
{
    
    
}

const QDateTime& DateTimeDecorator::value() const
{
    
    
    return implementation->value;
}

DateTimeDecorator& DateTimeDecorator::setValue(const QDateTime& value)
{
    
    
    if(value != implementation->value) {
    
    
        // ...Validation here if required...
        implementation->value = value;
        emit valueChanged();
    }

    return *this;
}

QString DateTimeDecorator::toIso8601String() const
{
    
    
    if (implementation->value.isNull()) {
    
    
        return "";
    } else {
    
    
        return implementation->value.toString(Qt::ISODate);
    }
}

QString DateTimeDecorator::toPrettyString() const
{
    
    
    if (implementation->value.isNull()) {
    
    
        return "Not set";
    } else {
    
    
        return implementation->value.toString( "ddd d MMM yyyy @ HH:mm:ss" );
    }
}

QString DateTimeDecorator::toPrettyDateString() const
{
    
    
    if (implementation->value.isNull()) {
    
    
        return "Not set";
    } else {
    
    
        return implementation->value.toString( "d MMM yyyy" );
    }
}

QString DateTimeDecorator::toPrettyTimeString() const
{
    
    
    if (implementation->value.isNull()) {
    
    
        return "Not set";
    } else {
    
    
        return implementation->value.toString( "hh:mm ap" );
    }
}

QJsonValue DateTimeDecorator::jsonValue() const
{
    
    
    return QJsonValue::fromVariant(QVariant(implementation->value.toString(Qt::ISODate)));
}

void DateTimeDecorator::update(const QJsonObject& jsonObject)
{
    
    
    if (jsonObject.contains(key())) {
    
    
        auto valueAsString = jsonObject.value(key()).toString();
        auto valueAsDate = QDateTime::fromString(valueAsString, Qt::ISODate);  // yyyy-MM-ddTHH:mm:ss
        setValue(valueAsDate);
    } else {
    
    
        setValue(QDateTime());
    }
}

データ情報クラスのカプセル化

基本タイプがカプセル化された後、データ情報クラスをさらにカプセル化できます。データ情報クラスは、多くの基本型から構成される有機的なデータの集合であり、基本データ間には論理的な関係があります。例えば、消費者情報クラスには、文字列型の名前、整数型の年齢、文字列型のアドレス、文字列型の性別などが含まれる。データ情報クラスと基本型の対応は、1 対 1 または 1 対多の場合があります。たとえば、ある人の名前は 1 つだけですが、複数の住所を持つ場合があります。これは、カプセル化するときに考慮する必要があります。データ情報クラスのカプセル化クラス間の関係を次の図に示します。
ここに画像の説明を挿入
データ エンティティの基本クラスであるエンティティは、基本的なプロパティとメソッドを必要とするエンティティをカプセル化し、データ エンティティには複数の基本タイプのプロパティが含まれます。同時に、データ エンティティには他の複数のデータ エンティティが含まれる場合があります。たとえば、ユーザーが複数の車両などで複数のアカウントを持っている場合があります。

1. データ情報本体のカプセル化

Entity には、次のようなデータ情報エンティティの基本的なプロパティとメソッドが含まれています。

1、entity.h

#ifndef ENTITY_H
#define ENTITY_H

#include <map>
#include <QObject>
#include <QScopedPointer>
#include <data/data-decorator.h>
#include <data/entity-collection.h>

class Entity : public QObject
{
    
    
    Q_OBJECT

public:
    Entity(QObject* parent = nullptr, const QString& key = "SomeEntityKey");
    Entity(QObject* parent, const QString& key, const QJsonObject& jsonObject);
    virtual ~Entity();

public:
    //数据信息体对应的key值
    const QString& key() const;

    //数据信息类和Json结构之间的相互转换
    void update(const QJsonObject& jsonObject);
    QJsonObject toJson() const;

signals:
    //信息体集合发生变化
    void childCollectionsChanged(const QString& collectionKey);
    //包含的信息体发生变化
    void childEntitiesChanged();
    //包含的属性发生变化
    void dataDecoratorsChanged();

protected:
    //添加包含的信信息体
    Entity* addChild(Entity* entity, const QString& key);
    //添加包含的信息实体列表
    EntityCollectionBase* addChildCollection(EntityCollectionBase* entityCollection);
    //添加子属性
    DataDecorator* addDataItem(DataDecorator* dataDecorator);
protected:
    class Implementation;
    QScopedPointer<Implementation> implementation;
};

#endif

2、entity.cpp

#include "entity.h"
#include <QJsonArray>

class Entity::Implementation
{
    
    
public:
    Implementation(Entity* _entity, const QString& _key)
        : entity(_entity)
        , key(_key)
    {
    
    
    }
    Entity* entity{
    
    nullptr};
    QString key;
    std::map<QString, EntityCollectionBase*> childCollections;
    std::map<QString, Entity*> childEntities;
    std::map<QString, DataDecorator*> dataDecorators;
};

Entity::Entity(QObject* parent, const QString& key)
    : QObject(parent)
{
    
    
    implementation.reset(new Implementation(this, key));
}

Entity::Entity(QObject* parent, const QString& key, const QJsonObject& jsonObject)
    : Entity(parent, key)
{
    
    
    update(jsonObject);
}

Entity::~Entity()
{
    
    
}
const QString& Entity::key() const
{
    
    
    return implementation->key;
}

Entity* Entity::addChild(Entity* entity, const QString& key)
{
    
    
    if(implementation->childEntities.find(key) == std::end(implementation->childEntities)) {
    
    
        implementation->childEntities[key] = entity;
        emit childEntitiesChanged();
    }

    return entity;
}

EntityCollectionBase* Entity::addChildCollection(EntityCollectionBase* entityCollection)
{
    
    
    if(implementation->childCollections.find(entityCollection->getKey()) == std::end(implementation->childCollections)) {
    
    
        implementation->childCollections[entityCollection->getKey()] = entityCollection;
        emit childCollectionsChanged(entityCollection->getKey());
    }

    return entityCollection;
}

DataDecorator* Entity::addDataItem(DataDecorator* dataDecorator)
{
    
    
    if(implementation->dataDecorators.find(dataDecorator->key()) == std::end(implementation->dataDecorators)) {
    
    
        implementation->dataDecorators[dataDecorator->key()] = dataDecorator;
        emit dataDecoratorsChanged();
    }
    return dataDecorator;
}

void Entity::update(const QJsonObject& jsonObject)
{
    
    
    // Update data decorators
    for (std::pair<QString, DataDecorator*> dataDecoratorPair : implementation->dataDecorators) {
    
    
        dataDecoratorPair.second->update(jsonObject);
    }

    // Update child entities
    for (std::pair<QString, Entity*> childEntityPair : implementation->childEntities) {
    
    
        childEntityPair.second->update(jsonObject.value(childEntityPair.first).toObject());
    }

    // Update child collections
    for (std::pair<QString, EntityCollectionBase*> childCollectionPair : implementation->childCollections) {
    
    
        childCollectionPair.second->update(jsonObject.value(childCollectionPair.first).toArray());
    }
}

QJsonObject Entity::toJson() const
{
    
    
    QJsonObject returnValue;

    // Add data decorators
    for (std::pair<QString, DataDecorator*> dataDecoratorPair : implementation->dataDecorators) {
    
    
        returnValue.insert( dataDecoratorPair.first, dataDecoratorPair.second->jsonValue() );
    }

    // Add child entities
    for (std::pair<QString, Entity*> childEntityPair : implementation->childEntities) {
    
    
        returnValue.insert( childEntityPair.first, childEntityPair.second->toJson() );
    }

    // Add child collections
    for (std::pair<QString, EntityCollectionBase*> childCollectionPair : implementation->childCollections) {
    
    
        QJsonArray entityArray;
            for (Entity* entity : childCollectionPair.second->baseEntities()) {
    
    
            entityArray.append( entity->toJson() );
        }
        returnValue.insert( childCollectionPair.first, entityArray );
    }

    return returnValue;
}

2. データ情報収集のカプセル化

データ情報の集合とは、データ本体のリストをカプセル化することであり、例えば、ユーザーにはアドレスリストが含まれており、アドレスリストはアドレス情報の集合である。テンプレート操作を通じて、さまざまな情報エンティティのシリアル化と逆シリアル化を実現できます。情報収集の実現は次のとおりです。

#ifndef ENTITYCOLLECTION_H
#define ENTITYCOLLECTION_H

#include <QJsonArray>
#include <QJsonValue>
#include <QObject>

class Entity;
//基类声明集合变化的信号
class EntityCollectionObject : public QObject
{
    
    
    Q_OBJECT

public:
    EntityCollectionObject(QObject* _parent = nullptr) : QObject(_parent) {
    
    }
    virtual ~EntityCollectionObject() {
    
    }

signals:
    void collectionChanged();
};

//数据信息集合的基类
class EntityCollectionBase : public EntityCollectionObject
{
    
    
public:
    EntityCollectionBase(QObject* parent = nullptr, const QString& key = "SomeCollectionKey")
        : EntityCollectionObject(parent)
        , key(key)
    {
    
    }

    virtual ~EntityCollectionBase()
    {
    
    }

    QString getKey() const
    {
    
    
        return key;
    }

    virtual void clear() = 0;
    //json数组转成数据实体
    virtual void update(const QJsonArray& json) = 0;
    virtual std::vector<Entity*> baseEntities() = 0;

    template <class T>
    QList<T*>& derivedEntities();

    template <class T>
    T* addEntity(T* entity);

private:
    QString key;
};

//数据信息基类
template <typename T>
class EntityCollection : public EntityCollectionBase
{
    
    
public:
    EntityCollection(QObject* parent = nullptr, const QString& key = "SomeCollectionKey")
        : EntityCollectionBase(parent, key)
    {
    
    }

    ~EntityCollection()
    {
    
    }

    //清空列表
    void clear() override
    {
    
    
        for(auto entity : collection) {
    
    
            entity->deleteLater();
        }
        collection.clear();
    }
    //更新列表
    void update(const QJsonArray& jsonArray) override
    {
    
    
        clear();
        for(const QJsonValue& jsonValue : jsonArray) {
    
    
            addEntity(new T(this, jsonValue.toObject()));
        }
    }
   
    //获取列表
    std::vector<Entity*> baseEntities() override
    {
    
    
        std::vector<Entity*> returnValue;
        for(T* entity : collection) {
    
    
            returnValue.push_back(entity);
        }
        return returnValue;
    }
   
    //获取列表的引用
    QList<T*>& derivedEntities()
    {
    
    
        return collection;
    }
   
    //添加新的信息实体
    T* addEntity(T* entity)
    {
    
    
        if(!collection.contains(entity)) {
    
    
            collection.append(entity);
            EntityCollectionObject::collectionChanged();
        }
        return entity;
    }
private:
    QList<T*> collection;
};

template <class T>
QList<T*>& EntityCollectionBase::derivedEntities()
{
    
    
    return dynamic_cast<const EntityCollection<T>&>(*this).derivedEntities();
}

template <class T>
T* EntityCollectionBase::addEntity(T* entity)
{
    
    
    return dynamic_cast<const EntityCollection<T>&>(*this).addEntity(entity);
}

#endif

カプセル化されたデータ構造を使用する

1. 新しいビジネス データ タイプを定義する

カプセル化が完了したら、プロジェクトでカプセル化されたタイプを使用できます。ここでは、コンシューマー顧客を例として、基本的なタイプのカプセル化の使用方法を説明します。Customer コンシューマには、文字列型の名前、整数型の経過時間、およびアドレスのリストという 2 つの基本属性が含まれています。住所には市区町村の郵便番号などの情報が含まれており、住所の実装は次のとおりです。
1. address.h

#ifndef ADDRESS_H
#define ADDRESS_H

#include <QObject>
#include <data/string-decorator.h>
#include <data/entity.h>

class Address : public Entity
{
    
    
    Q_OBJECT
    Q_PROPERTY(StringDecorator* ui_building MEMBER building CONSTANT)
    Q_PROPERTY(StringDecorator* ui_street MEMBER street CONSTANT)
    Q_PROPERTY(StringDecorator* ui_city MEMBER city CONSTANT)
    Q_PROPERTY(StringDecorator* ui_postcode MEMBER postcode CONSTANT)
    Q_PROPERTY(QString ui_fullAddress READ fullAddress CONSTANT)

public:
    explicit Address(QObject* parent = nullptr);
    Address(QObject* parent, const QJsonObject& json);

    StringDecorator* building{
    
    nullptr}; //建筑
    StringDecorator* street{
    
    nullptr};   //街道
    StringDecorator* city{
    
    nullptr};     //城市
    StringDecorator* postcode{
    
    nullptr}; //邮政编码

    QString fullAddress() const;
};

#endif

2、アドレス.cpp

#include "address.h"

Address::Address(QObject* parent)
        : Entity(parent, "address")
{
    
    
    building = static_cast<StringDecorator*>(addDataItem(new StringDecorator(this, "building", "Building")));
    street = static_cast<StringDecorator*>(addDataItem(new StringDecorator(this, "street", "Street")));
    city = static_cast<StringDecorator*>(addDataItem(new StringDecorator(this, "city", "City")));
    postcode = static_cast<StringDecorator*>(addDataItem(new StringDecorator(this, "postcode", "Post Code")));
}

Address::Address(QObject* parent, const QJsonObject& json)
        : Address(parent)
{
    
    
    update(json);
}

QString Address::fullAddress() const
{
    
    
    return building->value() + " " + street->value() + "\n" + city->value() + "\n" + postcode->value();
}
基本属性に加えて、コンシューマ情報クラスには一連のアドレス情報も含まれており、対応する実装は次のとおりです。

1、顧客.h

#ifndef Customer_H
#define Customer_H

#include <QObject>
#include <QtQml/QQmlListProperty>
#include <data/string-decorator.h>
#include <data/int-decorator.h>
#include <data/entity.h>
#include <data/entity-collection.h>
#include <data/address.h>

class Customer : public Entity
{
    
    
    Q_OBJECT
    //QML访问的信息接口
    //年龄信息
    Q_PROPERTY( IntDecorator* ui_age MEMBER age CONSTANT )
    //姓名信息
    Q_PROPERTY( StringDecorator* ui_name MEMBER name CONSTANT )
    Q_PROPERTY( Address* ui_mainAddress MEMBER defaultAddr CONSTANT ) //默认地址
    //地址列表
    Q_PROPERTY( QQmlListProperty<Address> ui_address READ ui_address NOTIFY addresssListChanged)

public:
    explicit Customer(QObject* parent = nullptr);
    Customer(QObject* parent, const QJsonObject& json);

    IntDecorator* age{
    
    nullptr};       //年龄
    StringDecorator* name{
    
    nullptr};   //姓名
    Address* defaultAddr{
    
    nullptr};    //默认地址
    //地址列表
    EntityCollection<Address>* addresses{
    
    nullptr};
    //qml访问的地址列表
    QQmlListProperty<Address> ui_address();

signals:
    void addresssListChanged();
};

#endif

2、顧客.cpp

#include "customer.h"

Customer::Customer(QObject* parent)
    : Entity(parent, "Customer")
{
    
    
    age = static_cast<IntDecorator*>(addDataItem(new IntDecorator(this, "age", "年龄")));
    name = static_cast<StringDecorator*>(addDataItem(new StringDecorator(this, "name", "姓名")));
    defaultAddr = static_cast<Address*>(addChild(new Address(this), "defaultAddress"));
    addresses = static_cast<EntityCollection<Address>*>(addChildCollection(new EntityCollection<Address>(this, "address")));
}

Customer::Customer(QObject* parent, const QJsonObject& json)
    : Customer(parent)
{
    
    
    update(json);
}

QQmlListProperty<Address> Customer::ui_address()
{
    
    
    return QQmlListProperty<Address>(this, addresses->derivedEntities());
}

2. 新しいデータ型を使用する

新しいカプセル化タイプを使用することで、Json構造とデータクラスの相互変換を実現することができ、利用方法は以下の通りです。

#include "widget.h"
#include <QApplication>
#include <data/customer.h>
#include <data/address.h>

int main(int argc, char *argv[])
{
    
    
    QApplication a(argc, argv);
    //将json结构转换成一个数据类
    QJsonObject customer_json;
    Customer* customer = new Customer(NULL,customer_json);
    //名字变化处理
    QObject::connect(customer->name,&StringDecorator::valueChanged,[&](){
    
    });
    //年龄变化的处理
    QObject::connect(customer->age,&IntDecorator::valueChanged,[&](){
    
    });
    //默认地址变化的处理
    QObject::connect(customer->defaultAddr,&Address::dataDecoratorsChanged,[&](){
    
    });

    //修改数据
    customer->name->setValue("小明");
    customer->age->setValue(23);
    customer->defaultAddr->city->setValue("北京市");
    customer->defaultAddr->street->setValue("光明街道");
    customer->defaultAddr->building->setValue("6号楼");
    customer->defaultAddr->postcode->setValue("56788");

    //添加新地址
    Address* new_addr = new Address();
    new_addr->city->setValue("西河市");
    new_addr->street->setValue("细节街道");
    new_addr->building->setValue("6号楼");
    new_addr->postcode->setValue("56789");
    customer->addresses->addEntity(new_addr);

    //将数据类型转换成json数据结构
    QJsonObject json_object = customer->toJson();
    return a.exec();
}

このカプセル化により、データクラスと Json データ構造の間の相互変換を実現でき、すべての属性に説明情報が含まれるため、再利用と拡張に非常に役立ちます。

おすすめ

転載: blog.csdn.net/Cappuccino_jay/article/details/126604433