Registering all classes that inherit from a particular abstract class in Kotlin

Viewed 147

I have a singleton object called registry.

I also have an abstract base class, say Operation with an abstract field called name. I expect other people to subclass this abstract class and create classes denoting specific operations. I want to be able to store name -> Subclass mapping in my registry object.

Ideally, people who subclass this will not even know about this registration. But if that is unavoidable, I prefer them to write as little code as possible just next to their class declaration.

What is the best way of doing this?

1 Answers

The issue here is name being abstract.

If name were a constructor parameter, then you could simply put the code in the your abstract class's constructor. Every subclass, sub-subclass,… instance will call that constructor (directly or indirectly), so it would always get called. (That doesn't apply to a few special cases such as deserialisation and cloning, so you might have to handle those explicitly.)

However, your abstract class's constructor will get called before the sub(sub…)class constructor(s), and so the instance won't be fully initialised and its name property might not be available yet.

The options I see are:

  1. Refactor your class so that the name is a constructor parameter (and can't be changed thereafter), and add your code to the constructor. (If that restriction is feasible, then this is the simplest solution, both for you and for implementers of subclasses, who won't need to do anything extra.)

  2. Provide a method that subclasses can call once the name has been set up. (You'll have to make it clear in the documentation that subclasses must call that method; unfortunately, I don't know of any way to enforce it.)

  3. It may be possible to use annotations and compiler plug-ins and/or runtime libraries, similar to frameworks such as Spring. But I don't know the details, and that's likely to take much more work; it may also need your implementers to add plug-ins and/or libraries to their project, so probably isn't worth it unless you're doing a lot of other frameworky stuff too.

In each case, you can get the name value and the concrete subclass (using this::class or this::class.java), and store them in your registry. (It doesn't look like you're asking about the internals of the registry; I assume you have that side of things covered.)

Related