Results 1 to 3 of 3

Thread: Simple yet powerful object factory

  1. #1
    Join Date
    Jan 2006
    Posts
    31
    Thanked 5 Times in 4 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Simple yet powerful object factory

    An object factory lets you create objects by a value stored in a variable, as example the name of a class in a QString.

    The naive approach is to use a very big switch statment somewhere, making a long history short: this is not a good solution (googling around you will find a lot of reference on why this scheme is to avoid).

    I have created a very simple yet powerful object factory. Becasue an example is better then 1000 words here it goes a simple driver program.

    In case someone is interested I can post "factory.h" sources.

    File main.cpp:
    Qt Code:
    1. #include <QLabel>
    2. #include <QObject>
    3. #include <QTimer>
    4.  
    5. /* Works both with Qt3 and Qt4. No fancy Qt meta object info used,
    6.  * no QOBJECT macro or other specific Qt stuff. No derivation from
    7.  * Qt classes used. The only (easily portable) requirements are for
    8.  * a QMap and a QString, all remaining stuff is pure C++ with no
    9.  * other libraries involved. Finally no namespace pollution, only
    10.  * Register<> and Factory<> templates are visible.
    11.  */
    12. #include "factory.h" // just need to include this header
    13.  
    14. /* First (and only) thing to do is to 'register' a class with a proper factory
    15.  * in one IMPLEMENTATION FILE (not header!). You can choose any file you
    16.  * want as long as a declaration of your class is included.
    17.  * Probably you may want to register the class at the beginning of the file
    18.  * that implements your class, but this is up to you.
    19.  *
    20.  * The first name in 'Register' template instantation is the class to
    21.  * register, the second one is the base class of our hierarchy. We can
    22.  * have more hierarchies at the same time.
    23.  *
    24.  * We can register a class with a factory anywhere in a program, both in file
    25.  * scope (will be registered at startup with static data), as we see here, or
    26.  * in a function body (will be registered when the function is called).
    27.  */
    28. // teach QWidget's factory how to create a QLabel
    29. static Register<QLabel, QWidget> l("QLabel");
    30.  
    31. // teach QObject's factory how to create a QTimer
    32. static Register<QTimer, QObject> t("QTimer");
    33.  
    34. /* Of course you can (better) use an anonymous namespace in
    35.  * implemantation files to avoid the 'static' qualifier
    36.  */
    37. namespace {
    38. // no problem in re-registering the same class, old one will be overwritten
    39. Register<QTimer, QObject> w("QTimer");
    40.  
    41. // we can (optionally) provide our custom 'create' function, see later
    42. QLabel* customCreator() { return new QLabel("Function customCreator() was used"); }
    43. }
    44.  
    45. int main(int argc, char* argv[]) { // this simple driver program requires Qt4
    46.  
    47. QApplication app(argc, argv);
    48.  
    49. // now we can start creating objects, as example a QTimer
    50. QObject* t = Factory<QObject>::instance().create("QTimer");
    51. if (dynamic_cast<QTimer*>(t)) qDebug("It's a timer"); // Yes. It is!
    52.  
    53. // we can use any string expression to pass the class name to our factory
    54. QString myName = "Label";
    55. QWidget* lbl = Factory<QWidget>::instance().create("Q" + myName);
    56. qDebug("Class of lbl is %s", lbl->metaObject()->className()); // Yes. It's a QLabel
    57.  
    58.  
    59. { // local scope here, could be any function body
    60.  
    61. // we can use any alias when registering a class with a factory,
    62. // in this case we call 'myObject' a QObject class
    63. Register<QObject, QObject> localVar("myObject");
    64.  
    65. } // variable 'localVar' goes out of scope here and is deleted...
    66.  
    67. // ...but we can still create a "myObject" object anywhere in the program
    68. QObject* obj = Factory<QObject>::instance().create("myObject");
    69. qDebug("Class of obj is %s", obj->metaObject()->className()); // it's a QObject
    70.  
    71.  
    72. // we can always redefine an object creator, as example using our
    73. // custom one instead of the default supplied...
    74. Register<QLabel, QWidget> dummy("QLabel", &customCreator);
    75.  
    76. // ...so that any new QLabel will be created with our
    77. // customCreator() function
    78. QLabel* lbl2 = dynamic_cast<QLabel*>
    79. (Factory<QWidget>::instance().create("QLabel"));
    80.  
    81. // "Function customCreator() was used"
    82. qDebug("%s", lbl2->text().toLatin1().constData());
    83.  
    84. delete t; // objects can be deleted as usual when no more needed
    85. delete lbl;
    86. delete obj;
    87. delete lbl2;
    88.  
    89. return 0;
    90. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by jacek; 23rd August 2007 at 21:25. Reason: missing [code] tags

  2. #2
    Join Date
    Jan 2006
    Location
    travelling
    Posts
    1,116
    Thanks
    8
    Thanked 127 Times in 121 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: Simple yet powerful object factory

    Please use the [ C O D E ] tag... And also think about giving the interesting part : the factory header...
    Current Qt projects : QCodeEdit, RotiDeCode

  3. #3
    Join Date
    Jan 2006
    Posts
    31
    Thanked 5 Times in 4 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: Simple yet powerful object factory

    That's the interesting part: file factoy.h

    The only difference with the example before is that I have added an
    helper to create an object:

    Before

    QObject* t = Factory<QObject>::instance().create("QTimer");

    Now simply

    QObject* t = new_object<QObject>("QTimer");


    Qt Code:
    1. /*
    2. Author: Marco Costalba (C) 2005-2007
    3. */
    4. #ifndef FACTORY_H
    5. #define FACTORY_H
    6.  
    7. #include <QMap>
    8. #include <QString>
    9.  
    10. template<class Base> Base* new_object(const QString&);
    11.  
    12. template<class Base> class Factory { // singleton class, one each base class
    13. Factory() {}
    14. Factory(const Factory&);
    15. Factory& operator=(const Factory&);
    16. ~Factory() { qDeleteAll(creators); }
    17.  
    18. Base* create(const QString& nm) const {
    19. return (creators.contains(nm) ? creators[nm]->create() : NULL);
    20. }
    21. friend Base* new_object<>(const QString&);
    22. public:
    23. class Creator { public:
    24. virtual ~Creator() {}
    25. virtual Base* create() const = 0;
    26. };
    27. static Factory& instance() {
    28. static Factory p_instance;
    29. return p_instance;
    30. }
    31. void unregisterCreator(const QString& nm) {
    32. if (creators.contains(nm)) {
    33. delete creators[nm];
    34. creators.remove(nm);
    35. }
    36. }
    37. void registerCreator(const QString& nm, const Creator* c) {
    38. unregisterCreator(nm);
    39. creators.insert(nm, c);
    40. }
    41. private:
    42. QMap<QString, const Creator*> creators;
    43. };
    44.  
    45. template<class Base> Base* new_object(const QString& nm) {
    46. return Factory<Base>::instance().create(nm);
    47. }
    48.  
    49. template<class Derived, class Base> class Register {
    50. typedef Derived* (*CreateFn) ();
    51. class Creator : public Factory<Base>::Creator { public:
    52. Creator(CreateFn fn) : createFn(fn) {}
    53. virtual Derived* create() const {
    54. return (createFn ? createFn() : new Derived(NULL));
    55. };
    56. CreateFn createFn;
    57. };
    58. public:
    59. Register(const QString& nm, CreateFn fn = NULL) {
    60. Factory<Base>::instance().registerCreator(nm, new Creator(fn));
    61. }
    62. };
    63.  
    64. #endif
    To copy to clipboard, switch view to plain text mode 

  4. The following 2 users say thank you to mcostalba for this useful post:

    Landkeeper (14th January 2013), pkohut (1st January 2011)

Similar Threads

  1. Sending simple object via udp...with a twist
    By the scribe in forum Qt Programming
    Replies: 1
    Last Post: 6th June 2007, 11:16

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.