16.1.1.  Abstract Factory

[ fromfile: factory.xml id: abstractfactory ]

AbstractFactory, defined in Example 16.1, is a simple class:

Example 16.1. src/libs/dataobjects/abstractfactory.h

[ . . . . ]
class DOBJS_EXPORT AbstractFactory
{
  public:
    virtual QObject* newObject (QString className,
                                QObject* parent=0) = 0;
    virtual ~AbstractFactory();

};
[ . . . . ]

The newObject() method is pure virtual, so it must be overridden in derived classes. Example 16.2 shows a concrete class derived from AbstractFactory.

Example 16.2. src/libs/dataobjects/objectfactory.h

[ . . . . ]
class DOBJS_EXPORT  ObjectFactory : public AbstractFactory {
  public:
    ObjectFactory();
    virtual QObject* newObject (QString className, QObject* parent=0);
 protected:
    QHash<QString, QMetaObject> m_knownClasses;
};
[ . . . . ]

We have defined ObjectFactory so that it knows how to create two concrete types. Because it is possible for any QString to be supplied to newObject(), ObjectFactory handles the case when an unknown class is passed. In this case, it returns a pointer to a generic QObject and sets the dynamic property, className, to let other functions (such as the xml export routine) know that this object is "spoofing" an object of another class.

Example 16.3. src/libs/dataobjects/objectfactory.cpp

[ . . . . ]

ObjectFactory::ObjectFactory() {
    m_knownClasses["UsAddress"] = UsAddress::staticMetaObject;
    m_knownClasses["CanadaAddress"] = CanadaAddress::staticMetaObject;
}

QObject* ObjectFactory::newObject(QString className, QObject* parent) {
    QObject* retval = 0;
    if (m_knownClasses.contains(className)) {
        const QMetaObject& mo = m_knownClasses[className];
        retval = mo.newInstance();      1
        if (retval == 0) {
            qDebug() << "Error creating " << className;
            abort();
        }
    } else {
        qDebug() << QString("Generic QObject created for new %1")
                    .arg(className);
        retval = new QObject();
        retval->setProperty("className", className);
    }
    if (parent != 0) retval->setParent(parent);
    return retval;
}

1

Requires Qt 4.5 or later.


Example 16.4 shows an example use of the Q_INVOKABLE macro with the constructor for the UsAddress class.

Example 16.4. src/libs/dataobjects/address.h

[ . . . . ]

class DOBJS_EXPORT UsAddress : public Address {
    Q_OBJECT
  public:
    Q_PROPERTY( QString State READ getState WRITE setState );
    Q_PROPERTY( QString Zip READ getZip WRITE setZip );
    explicit Q_INVOKABLE UsAddress(QString name=QString(), QObject* parent=0)
                                  : Address(name, parent) {}
  protected:
    static QString getPhoneFormat();
  public:
[ . . . . ]

  private:
    QString m_State, m_Zip;
};