///////////////////////////////////////////////////////////////////////// // client.cpp - uses implementation static library // // Does not require rebuilding client if you modify // // implementation, since client binds to interface and // // uses an object factory. // // // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2006 // ///////////////////////////////////////////////////////////////////////// // build process // ///////////////////////////////////////////////////////////////////////// // required files: // // ExampleInterface.h, factory.h client.cpp implementation.lib // // build commands: // // cl /EHa client.cpp implementation.lib // // note: /EHa enables exception handling. // ///////////////////////////////////////////////////////////////////////// #include #include "factory.h" // object factory #include "ExampleInterface.h" // interface ///////////////////////////////////////////////////////////////////// // Note that client represents a policy layer that does not include // any implementation layer headers. It includes just the factory // and interface headers, which contain no implementation details. // There is no reference to derived types in either of these headers. // void main() { std::cout << "\n Demonstate Programming to Interfaces " << "\n ======================================\n"; ////////////////////////////////////////////////////////////////// // Create an implementation factory and use its interface to // register its objects with the factory. objFactory objFactory; ExampleInterface::registerObjects(objFactory); ///////////////////////////////////////////////////////////////// // Policy needs to know how to access the ids of the implementation // classes it uses, but does not need to bind to the class names. ExampleInterface* pExample1 = objFactory.makeObj(ExampleInterface::type(1)); if(pExample1) { pExample1->announcer(); // polymorphic call delete pExample1; } ExampleInterface *pExample2 = objFactory.makeObj(ExampleInterface::type(2)); if(pExample2) { pExample2->announcer(); // polymorphic call delete pExample2; } std::cout << std::endl; std::cout << "\n The objFactory delivers, via ExampleInterface pointers," << "\n objects that derive from ExampleInterface. That" << "\n interface provides a protocol for clients of all" << "\n derived class objects, like Example1 and Example2," << "\n to use, without needing to bind to the concrete" << "\n derived class of the objectthey are using."; std::cout << "\n\n"; } #ifndef EXAMPLEINTERFACE_H #define EXAMPLEINTERFACE_H /////////////////////////////////////////////////////////////////////// // ExampleInterface.h - provides protocol for clients to use with // // implementation classes // // // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2004 // /////////////////////////////////////////////////////////////////////// #include #include "factory.h" /////////////////////////////////////////////////////////////// // Example abstract class declaration // - provides protocol for derived classes Example1 and Example2 class ExampleInterface { public: virtual ~ExampleInterface() { } virtual void announcer() = 0; static void registerObjects(objFactory &factory); static std::string type(int n); }; #endif Demonstate Programming to Interfaces ====================================== object of class Example1 object of class Example2 The objFactory delivers, via ExampleInterface pointers, objects that derive from ExampleInterface. That interface provides a protocol for clients of all derived class objects, like Example1 and Example2, to use, without needing to bind to the concrete derived class of the objectthey are using. #ifndef FACTORY_H #define FACTORY_H /////////////////////////////////////////////////////////////////////// // factory.h - declares object factory // // ver 2.0 // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2004 // /////////////////////////////////////////////////////////////////////// /* The objFactory class creates an object of the base or any derived class, attached to a base pointer. The user does not need to know the object's type. You need to treat the factory like a smart new operator. It creates an object on the heap. It's up to you to delete it. objFactory class declaration - The odd type T*(*)(), in the second argument of the map is the type of a function pointer for creation functions of signature T* somefun(). - In the reg function, the second declaration is Type arg where Type is T*(*)() and arg is pFun. */ #include #include typedef std::string classID; template class objFactory { public: objFactory(); void reg(classID id, Base*(*pFun)()); Base* makeObj(classID id); private: static std::map registry; }; // ///////////////////////////////////////////////////////////////////////// // define the static instance of the class registry template std::map objFactory::registry; //----< construct objFactory >------------------------------------------- template objFactory::objFactory() { } //----< register a static member creation function >--------------------- template void objFactory::reg(classID id, Base*(*pFun)()) { registry[id] = pFun; } //----< create an instance of a creatable class >------------------------ // // returns null pointer if object not found in registry // template Base* objFactory::makeObj(classID id) { Base *theObject = NULL; std::map::const_iterator entry = registry.find(id); if(entry != registry.end()) theObject = entry->second(); // using static creational function else theObject = 0; return theObject; } #endif #ifndef CREATABLE_H #define CREATABLE_H /////////////////////////////////////////////////////////////////////// // creatable.h - declares creatable interface and object factory // // ver 2.0 // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2004 // /////////////////////////////////////////////////////////////////////// /* Module Operations: ================== The creator class defines a creation policy for objects that can be created with an instance of class objFactory. The creator class is template-based where its template parameters defines the class of the object to be created and its base. Creatable classes inherit publically from the creator class to declare and implement two functions: - a create function that returns a new instance of the class via a pointer whose type is the class or a base type. - a function called classID() that returns a string holding the class name. */ ///////////////////////////////////////////////////////////////////////// // build process // ///////////////////////////////////////////////////////////////////////// // required files: // // creatable.h, implementation.h, implementation.cpp // // // // compiler command: // // cl /GX /GR implementation.cpp // // // // note: /GX enables exception handling. // // /GR enables RTTI which we need in order to use dynamic_cast. // // In the IDE you can enable RTTI on the Project Settings // // menu. Select C/C++ tab and select C++ language from the // // category combo box. Check the box for enabling RTTI. // // // ///////////////////////////////////////////////////////////////////////// // #include "factory.h" ///////////////////////////////////////////////////////////////////////// // creator class declaration // - provides a creational policy template class creator { public: virtual ~creator() { } static B* create(); // a value in objFactory map static classID id(); // a key in objFactory map }; //----< returns an object of type D via a type B pointer >--------------- // // will fail to compile unless D is B or derived from B // template B* creator::create() { return new D; } //----< return class name >---------------------------------------------- template classID creator::id() { std::string temp = typeid(D).name(); // returns "class name" return temp; } #endif #ifndef IMPLEMENTATION_H #define IMPLEMENTATION_H ///////////////////////////////////////////////////////////////////////// // implementation.h - provides class declarations for // // implementation classes // // // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2006 // ///////////////////////////////////////////////////////////////////////// // build process // ///////////////////////////////////////////////////////////////////////// // required files: // // creatable.h, implementation.h, implementation.cpp // // // // build commands: // // cl /EHsc /GR /c implementation.cpp // // lib implementation.obj // // // // note: /EHsc enables exception handling. // // /GR enables RTTI which we need in order to use dynamic_cast. // // In the IDE you can enable RTTI on the Project Settings // // menu. Select C/C++ tab and select C++ language from the // // category combo box. Set Runtime Type Info to yes. // // /c limits processing to compilation, e.g., no link, which // // generates an obj. // // // ///////////////////////////////////////////////////////////////////////// #include "ExampleInterface.h" #include "Creatable.h" /////////////////////////////////////////////////////////////// // Example1 class declaration - example creatable class class Example1 : public ExampleInterface, public creator { public: virtual void announcer(); }; ///////////////////////////////////////////////////////////////////////// // Example2 class declaration - example creatable class class Example2 : public ExampleInterface , public creator { public: virtual void announcer(); }; #endif ///////////////////////////////////////////////////////////////////////// // implementation.cpp - provides implementation for // // implementation layer classes // // and for static members of interface // // // // Jim Fawcett, CSE687 - Object Oriented Design, Spring 2004 // ///////////////////////////////////////////////////////////////////////// #include #include "implementation.h" //----< virtual function displays class identity >------------- void Example1::announcer() { std::cout << "\n object of " << id(); } //----< virtual function displays class identity >------------- void Example2::announcer() { std::cout << "\n object of " << id(); } //----< register objects of this module for client >----------- void ExampleInterface::registerObjects(objFactory &factory) { factory.reg(Example1::id(),Example1::create); factory.reg(Example2::id(),Example2::create); } //----< let client identify the object needed >---------------- std::string ExampleInterface::type(int n) { switch(n) { case 1 : return typeid(Example1).name(); case 2 : return typeid(Example2).name(); default : throw "unknown class in ExampleInterface::type()"; } return "unknown"; }