[ fromfile: factory.xml id: creationalrules ]
You can design a class to have a creation rule, such
as: All new Customers must be created indirectly through a CustomerFactory.
You can enforce this rule by defining only non-public constructors.
In particular, make sure that you make the copy constructor and the assignment operator non-public.
If you omit them from the class definition, the compiler will supply public versions of these two member functions, thus producing two “loopholes” in your creation rule.
For example, this might permit clients to create Customer instances that are not children of your factory (which could lead to memory leaks).
It is important to document this rule clearly in your class definition as we did with the comment in Example 17.9.
Example 17.9. src/libs/customer/customer.h
In Example 17.9,
the constructors are protected.
[49]
CustomerFactory is declared to be a friend class inside Customer.
This gives CustomerFactory permission to access the non-public members of Customer.
In this way, we have made it impossible for client code to create Customer objects except through the CustomerFactory.
In Example 17.10, we have a similar setup with the various Address classes.
The base class, Address, is abstract.
Example 17.10. src/libs/dataobjects/address.h
[ . . . . ]
class DOBJS_EXPORT Address : public ConstrainedDataObject {
Q_OBJECT
public:
[ . . . . ]
protected:
Address(QString addressName = QString()) {
setObjectName(addressName);
}
public:
virtual Country::CountryType getCountry() = 0;
[ . . . . ]
private:
QString m_Line1, m_Line2, m_City, m_Phone;
};
In the derived classes, defined in Example 17.11 we have protected the constructors and given friend status to a factory, this time DataObjects::ObjectFactory.
This gives ObjectFactory permission to access the non-public members of UsAddress and CanadaAddress.
Example 17.11. 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 );
friend class ObjectFactory;
protected:
UsAddress(QString name=QString()) : Address(name) {}
static QString getPhoneFormat();
public:
static void initConstraints() ;
[ . . . . ]
private:
QString m_State, m_Zip;
};
class DOBJS_EXPORT CanadaAddress : public Address {
Q_OBJECT
public:
Q_PROPERTY( QString Province READ getProvince
WRITE setProvince );
Q_PROPERTY( QString PostalCode READ getPostalCode
WRITE setPostalCode );
friend class ObjectFactory;
protected:
CanadaAddress(QString name=QString()): Address(name) {}
static QString getPhoneFormat();
public:
static void initConstraints() ;
[ . . . . ]
private:
QString m_Province, m_PostalCode;
};
It is now impossible to create Address objects except through the factory or from the derived classes.
| Note | |
|---|---|
If you are writing a multi-threaded application that uses an ObjectFactory, you need to be careful about the ownership of objects. Making a QObject the parent of a child in another thread will result in an error message such as the following one: New parent must be in the same thread as the previous parent", file kernel/qobject.cpp, line 1681 Aborted
To make our ObjectFactory work in a multi-threaded environment, we can:
|
| Generated: $Date: 2009-09-08 12:15:32 -0400 (Tue, 08 Sep 2009) $ | © 2009 Alan Ezust and Paul Ezust. |