1 / 15

Extensible Factories

Extensible Factories. Bonus Material – Not Examinable. Contents. Interface / Factory Recap Limitations of Factory Functions Extensible Factory Functions Extensible Factories Usage. Interfaces Recap. In C++, an interface is a class that has: No member variables

burton
Télécharger la présentation

Extensible Factories

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Extensible Factories Bonus Material – Not Examinable

  2. Contents • Interface / Factory Recap • Limitations of Factory Functions • Extensible Factory Functions • Extensible Factories Usage

  3. Interfaces Recap • In C++, an interface is a class that has: • No member variables • Only pure virtual functions • Prototype with no implementation • Only defines functions & does not implement them • We cannot create objects with pure virtual functions • Inherited implementation classes provide the code • A partial implementation is a kind of abstract class • An interface class defines the functionality • The implementation classes provide the functionality for different contexts

  4. Interface Example class IEntity // Interface { public: virtual void Update( float frameTime ) = 0; virtual void AI() = 0; } // Partial implementation – abstract class class CMovableEntity : public IEntity { public: void Update( float frameTime ){ m_Position += m_Velocity * frameTime;} virtual void AI() = 0; // Still pure virtual protected: CVector3 m_Position, m_Velocity; }

  5. Interface Example // Complete implementation class CShipEntity : public CMovableEntity { public: void Update( float frameTime ){ m_HP += m_Damage; CMovableEntity::Update(); // Call base class Update } void AI() // (lol) { m_Velocity.x = Random(-10.0f, 10.0f); m_Velocity.z = Random(-10.0f, 10.0f); } private: int m_HP, m_Damage; }

  6. Factory Functions • Factory functions make objects of a specific type • Typically used to create an object derived from an interface or abstract class • Without coupling to the inherited classes • A factory creates specific implementation classes • Say we use the IEntity class generally in our code • If we want to create a ship entity in our game • We create a factory function: IEntity* CreateEntity( EntityType type ); • Now we don’t need to refer to CShipEntity: IEntity* newShip = CreateEntity( ShipType );

  7. Factory Function Example // Factory.h - Can be included anywhere – no coupling // Enumeration of types created by factory function enum { ShipType, PlanetType, }; // etc. IEntity* CreateEntity( EntityType type ); // Prototype // Factory.cpp - coupled to all types that can be created #include “CShipEntity.h” // Factory function – creates objects of a given type IEntity* CreateEntity( EntityType type ) { if (type == ShipType) { return new CShipEntity; } else // ...create other supported types }

  8. Factory Function Example // Game code // Include factory prototype / entity types // No linkage to actual entity classes – no coupling #include “Factory.h” // ... // Create entities – no need to refer to actual classes IEntity* ship1 = CreateEntity( shipType ); IEntity* ship2 = CreateEntity( shipType ); IEntity* planet1 = CreateEntity( planetType ); // ... // Generic programming with entities ship1->Update(); // Entity class contains behaviour ship1->Render(); // etc...

  9. Limitations of Factories • The factory function needs the definition of CShipEntity, and every other type it creates • “CShipEntity.h” must be included for the factory code • Usually means factories having their own source file • Factories are coupled to all the objects they create • So we need to recode/compile the factory every time we add a new type for it to create • Can’t add new types at runtime • Limits use for scripting / modding etc.

  10. Extensible Factories • More general approach is an extensible factory • A factory that can create objects of any class without needing the specific class definitions • It can only create objects with the same base class • But only needs the base class definition • We must explicitly register each new class before being able to create its objects • Unregister them when not needed anymore • This can be made quite automatic in C++ • Using templates to help…

  11. Simple Extensible Factory Class • Provide each inherited class with a “Maker” function, which can create objects of that class • Register new types with type ID and “Maker” function ptr // Factory to create any class inherited from Ientity // Note this is a factory class, not just a function class ExtensibleEntityFactory { public: // EntityMaker is a function pointer type void Register( EntityType type, EntityMaker maker ); void Unregister( EntityType type ); IEntity* Create( EntityType type );// Actual factory fn private: // Store hash map from entity types (key) to maker // functions to implement the above functions };

  12. Simple Extensible Factory Usage • Define some types IDs: enum EntityTypes { ShipType, PlanetType }; • Define “maker” functions for our types… IEntity* ShipMaker() { return new CShipEntity; } IEntity* PlanetMaker() { return new CPlanetEntity; } • Create our factory class and register our types ExtensibleFactory EntityFactory; EntityFactory.Register( ShipType, ShipMaker ); EntityFactory.Register( PlanetType, PlanetMaker ); • Now create objects as usual IEntity* ship1 = EntityFactory.Create( ShipType );

  13. Issues with Simple Approach • In this form we get little benefit over the original basic factory function • We must manually define a new type ID for each class • And hand code a “maker” function for each • Problems with coupling still present • We can generalise type IDs and maker functions • Use a class specific value instead of an enum for IDs • Static class member (UID or string) or perhaps use RTTI • Use a template to define a generic maker function • Assume maker functions all have same prototype

  14. Extensible Factory Usage • ID defined in the class: class CShipEntity{ static string ID = “ShipType”; ... } • All possible maker functions defined by a single template: template <class EntityType> IEntity* EntityMaker() { return new EntityType; } • Create our factory class and register our types ExtensibleFactory EntityFactory; EntityFactory.Register( EntityMaker<CShipEntity> ); • This is simplified for brevity - see Rabin for further details and an implementation

  15. Extensible Factory Usage • Extensible factories are advanced, but allow for much more flexible entity set-up • Simplify script-based set-up • Allow DLL usage (dynamic link library) - program add-ons can be created after the program is complete • Extensible factories can be used in other areas • An extensible resource factory is a very good idea • Allows for greater flexibility in the types of data file used • Again allowing for new data file types to be used without the need to recompile the core engine

More Related