Search code examples
c++design-patternsprototype-pattern

configuring app dynamically using prototype pattern


I am reading about prototype pattern by GoF book. Here is the text snippet

Configuring an application with classes dynamically: Some runtime environments let you load classes into an application dynamically. The prototype pattern is the key to exploiting such facilities in a language like C++.

An application that wants to create instances of a dynamically loaded classes won't be able to reference its constructor statically. Instead, runtime environment creates an instance of each class automatically when it's loaded, and registers with a prototype manager. Then the application can ask the prototype manager for newly loaded classes, classes that weren't ;omled with the program orginally

My questions on above

  1. What does author mean by "An application that wants to create instances of a dynamically loaded classes won't be able to reference its constructor statically" ? For example if we use dynamic link library I can still create object using new so what does author mean by we won't be able to reference constructor statically?

  2. Request to give an example how prototype pattern is used to exploit load classes application dynamically.


Solution

  • My 50 cents on this :

    1. I believe the author is referring to situations where you don't have the class definitions in the symbols library, however you want to instantiate objects, and pass them to the library consumer functions (so you are the memory owner, the shared library is the consumer , but you don't have access to the concrete classes inside the library )
    2. Example ( I will write one from the top of my head to underline a scenario where it would be useful then I will write another one that I actually bumped into)

      Having a dynamic library TextEditorWidgets.dll and your main application , the TextEditorWidget exposes an abstract prototype TEWPrototype , and a factory method of getting certain prototypes according to let's say a string identifier.

      Having the factory method exposed from the dll defined as :

      TEWPrototype* TEWPrototype::getPrototypeFor(string identifier)
      {
            TEWPrototype*  result;
            if (identifier == "SomeWidget")
            {
             result = ConcreteSomeWidgetPrototype;
            } else if ...
            return result;
      }
      

      Inside your application you can use the following code :

      {
        vector<TEWPrototype*> allocatedWidgets;
        ...
        TEWPrototype* SomeWidget = TEWPrototype::getPrototypeFor("SomeWidget").clone();// you are now the memory owner
        allocatedWidgets.push_back(SomeWidget); // keep for deletion
        TextEditorWidgetsHandle->doSomethingWithTheWidget(SomeWidget);// pass the instantiation to the consumer who knows the widget full definition
      }
      

      In the example above you have the following pros as the app develoer :

      • you will control what the dll allocates , when and how
      • you will control if the widgets get deleted or not through the lifetime of the application

      The pros as the dll developer :

      • you will be able to add new Widgets while providing backwards functionality
      • you have the guarantee that nobody will use your internal widgets functionality outside the .dll

    Practical example :

    While working on a game , new entities were created by the game development team, and we needed a fast way to give the Designers the new objects for them to add into the game scene. We had our own in house editor, so we had control over the design tool.

    The approach was to have the World Editor load .dlls , then expose in the editor menus what objects were loaded in the dlls. The editor didn't know what classes were inside the dlls, it only knew about them having a draw and a setPosition function (and some other things).

    When the dll was loaded , inside the editor, the name of the object was added into an object prototype manager (basically we had a static function getAvailableObjects and after dll load, we would query that in order to get the strings).

    When a Designer was choosing from a menu an object (let's say for example Crate), then a new instance of that object was created that was drawn inside the editor , and the designer could move it around.

    The editor couldn't instantiate the object by itself because he knew nothing about the size of the object nor about his constructor. However we had pre-instantiated objects for each type, that were getting cloned each time the Artist chosed to create a "new" Crate.

    The preinstantiated objects were also used in the preview .

    When the development team released a new set of entities , we just provided the new dll to the Designers, and they would only need to "refresh" the editor an BOOM : magic happened : new objects in the menu .

    As an alternative, an abstract factory can provide kind of the same functionality.