【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、datadecorator.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、enumeratordecorator.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、enumeratordecorator.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、datetimedecorator.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、datetimedecorator.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());
    }
}

数据信息类封装

封装好了基本类型就可以进一步封装数据信息类了。数据信息类就是一个有很多基本类型组合成的一个有机的数据集合整体,基本数据之间都是有逻辑关系的。比如消费者信息类就包含:字符串类型的姓名、整型的年龄、字符串类型的地址、字符串类型的性别等等。数据信息类和基本类型之间的对应关系有一对一的,也有一对多的,比如一个人只有一个名字,但可能有多个地址,在封装的时候需要考虑到这点。数据信息类的封装类之间的关系如下图所示:
在这里插入图片描述
数据实体的基类Entity封装实体需要基本属性和方法,一个数据实体包含多个基本类型的属性。同时一个数据实体可能包含多个其它的数据实体,比如一个用户可以拥有多量车多个账户等等。

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为例说明一下封装的基本类型的使用方法。Customer消费者包含两个基本属性字符串类型的姓名,整型的年龄,以及一个地址列表。地址包含城市街道邮政编码等信息,地址的实现方式如下:
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、address.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、customer.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、customer.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