I currently have an abstract class and multiple classes extending it. My problem is, that there has to be a way to create a variable number of instances of an extending class. The number of instances depends on some results from a prior operation and on the extending class itself.
For now, there is just a method separated from the classes which creates the instances. That is bad, because I want to be able to add a new extending class without changing code somewhere else in the program.
One way of solving the problem might be declaring a static method in the abstract class and overwriting int the extending class. But this is a bit messy because static methods and the concept of abstract classes do not really work well together. Also, defining abstract static methods is not allowed, which makes sense.
How would you solve this problem? Maybe a Factory class per extending class?
Best Answer
Following the design patterns proposed by the Gang of Four, you can use the Abstract Factory pattern to instantiate the different implementations. For instance:
This will isolate the responsibilities of creating instances of each subtype to its own classes, which can be placed in different namespaces or even separate libraries, allowing you to make isolated changes whenever needed.
But just the abstract factory pattern by itself is not very friendly to use, so a common practice is to make some sort of registry, where the rest of the system can query for a specific implementation. An example of that would be to use something similar to the Service Locator pattern, like so:
In the above example, I used a
string
for thekey
, but that was just to show how to register a factory in the locator using aDictionary
, which is the common approach. You can use anything that is relevant to your business rules, including your own objects as some sort of identifier/query object that tells the locator which implemention is required.Anyway, the point of a Locator-like object is to allow the system to add and/or remove different implementation os the
ParentFactory
at runtime. Following this pattern, you can separate the concrete implementations of your abstract class into different modules of the application, and have each module register its implementations on the locator at boot-up.