2

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?

4
  • 1
    That seems like a massive design smell to me. Why would you ever need a variable-depth inheritance tree? What is it that changes about your program so fundamentally at runtime? Commented Feb 18, 2016 at 10:47
  • Dynamic lookup, you can use a dictionary <Identifier, AbstractFactory>, is the way to solve your problem. When a user creates new implementation, a new factory is created (you'll need some logic for this), this factory is added to the collection and later looked up and used when necessary.
    – Andy
    Commented Feb 18, 2016 at 11:20
  • You might consider using composition instead of inheritance.
    – Erik Eidt
    Commented Feb 18, 2016 at 16:45
  • This is a bit unclear to me, what exactly is the constraint you have on object creation? Do you have a code example to illustrate?
    – user22815
    Commented Feb 18, 2016 at 18:43

1 Answer 1

1

Following the design patterns proposed by the Gang of Four, you can use the Abstract Factory pattern to instantiate the different implementations. For instance:

abstract class Parent {
   // some abstract behaviour
}

interface ParentFactory {
    Parent Make();
}

class Impl1 : Parent {
  // some concrete behaviour
}

class Impl1Factory : ParentFactory {
    public Parent Make() {
        return new Impl1();
    }
}

class Impl2 : Parent {
  // some concrete behaviour
}

class Impl2Factory : ParentFactory {
    public Parent Make() {
        return new Impl2();
    }
}

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:

class ParentFactories {
    private Dictionary<string, ParentFactory> factories;

    // constructor and such - probably private and following the Singleton pattern

    public void Register(string key, ParentFactory factory) {
        factories.Add(key, factory);
    }

    public Parent Make(string key) {
        return dictionary[key].Make();
    }
}

In the above example, I used a string for the key, but that was just to show how to register a factory in the locator using a Dictionary, 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.