Creator pattern
The Creator pattern includes a singleton, called the factory context, to compose the factories and the assignments from creation contexts to factories. Furthermore, the factory context provides operations to determine and get the factory for a certain context. In order to get a factory even if without passing a creation context to the factory context, the factory context is prepared with a default context that is passed to the factory context beforehand by any other components of the respective system. The factory context may also implement a fallback algorithm for the case no default context has been provided.
All factories have at least one common generalization with a public "create" operation which implements the default behavior for the case the concrete factory has no implementation for a certain object type. For instance, the default behavior may instantiate the object to create generically or throw an exception. The former reduces the number of factory operations which must be implemented by hand, the latter asserts no object will be created erroneously due to a missing implementation. The concrete factories provide overloaded siblings of that general "create" operation to implement their concrete creation algorithms. The general "create" operation takes a creator as argument with the generalized creator type, while the operations in the concrete factories take a creator as argument with the respective concrete creator type. Thus, a missing implementation in the concrete factory will cause the general "create" operation to be invoked.
Moreover, the design with overloaded factory operations, taking a creator as argument, enables the creator to call the factory passing itself as an argument. As a result, the call will be dispatched to the respective factory implementation as intended. This way the Creator pattern makes effectively use of a double dispatch. This means the factory operation is choosen by the type of the creator, which is choosen by the client (or passed by the client), and the concrete factory type is choosen by the creation context, which is choosen by the client (or any other component of the respective system) as well.
To create any object the client just needs to know which type of object shall be created (to create the respective creator) - and only in individual cases the client passes an individual creation context to the creator. The client only depends on the creator type and the type to create the object from. The creator type is just a sibling of that type to create the object from and resides in the same location or in a subpackage. So the dependency from the client to the creator type is just of a similar quality as the dependency from the client to the type to create the object from - and hence to be considered as harmless (in terms of invasiveness, removability, project structures and other impacts). The client is effectively decoupled from the rest of the creational framework, in particular the factories.
As a rough example for a possible sequence:
The client instantiates the creator and passes some necessary arguments to the creator. After the client called the "create" operation on the creator, but in this case without passing an individual creation context, the creator calls the factory context to get the default creation context. With that creation context the creator calls the factory context again to get the assigned factory. Then the creator calls that factory passing itself as argument. That call is dispatched to the respective operation in the factory where the implementation can access the concrete type of the creator to get the necessary arguments originally set by the client. With these arguments the factory creates the object as intended, but from an extension of that object type, and returns it to the creator finally returning it to the client. The client then uses the returned object as the intended type, not knowing the concrete type of that object.
Seiten |