meeting -*- Outline -*- ** Singleton (23.4) copy figure 23.5, 23.7 See also Gamma et al., pp. 127ff So who creates the factory itself? How is the factory accessed? Q: would be a good idea to pass the ServicesFactory class around the program? it usually involves more coupling than would be desirable Q: how many instances of the factory are needed? Just one this motivates the singleton pattern... ------------------------------------------ SINGLETON (23.4) Problem: How to ensure that a class has only one instance? How to provide global access to a single instance object? How to allow the instance to be extended by subtyping, without affecting clients? Solution: Use a static method (class operation) to return the instance. Hide the class's constructor. Example: ------------------------------------------ not the underlining in the attribute and methods of the class diagram ------------------------------------------ // $RCSfile: ServicesFactory.h,v $ #ifndef ServicesFactory_h #define ServicesFactory_h #include "AccountingAdapter.h" class ServicesFactory { private: AccountingAdapter * accountingAdapter; // ... public: virtual AccountingAdapter * getAccountingAdapter(); // ... static ServicesFactory * Instance(); protected: // hide the default constructor ServicesFactory(); // hide the copy constructor ServicesFactory(ServicesFactory &sf); private: static ServicesFactory * _instance; }; #endif ------------------------------------------ ------------------------------------------ // $RCSfile: ServicesFactory.cpp,v $ #include "ServicesFactory.h" #include #include "SAPAccountingAdapter.h" #include "TopAccountingAdapter.h" AccountingAdapter * ServicesFactory::getAccountingAdapter() { const char *sysname = getenv("ACCOUNTINGSYSTEM"); if (strcmp(sysname,"SAP") == 0) { return new SAPAccountingAdapter(); } else if (strcmp(sysname,"Top") == 0) { return new TopAccountingAdapter(); } else { // ... return 0; } } ServicesFactory * ServicesFactory::Instance() { if (_instance == 0) { _instance = new ServicesFactory(); } return _instance; } // need to initialize _instance so the // Instance method has somewhere to start ServicesFactory * ServicesFactory::_instance = 0; ------------------------------------------ *** UML shorthand interaction diagrams use the UML stereotype <> to suppress details about calling the getInstance message (see Fig. 23.6) *** implementation and design issues **** lazy vs. eager initialization the _instance variable is initialized lazily, only if required. In multi-threaded applications, this has to be done in a critical section, for example using a synchronized method in Java. Why not eager initialization? saves resources if the instance is never accessed there might not be enough information to initialize the instance statically C++ doesn't define order in which static constructors are called **** static methods instead of the singleton pattern Q: why not add a static method getAccountingAdapter to ServicesFactory? - one can refine the singleton class into subclasses. - singleton pattern permits having a few global objects instead of just a single one - problems with RMI and static methods *** related patterns often used for factory objects and facade objects. ** summary of access to external services with varying interfaces (23.5) We used the adapter, factory, and singleton patterns to provide protective variations from varying interfaces of external tax calculators, accounting systems, and so on. See figure 23.7.