Ginger McMurray
Ginger McMurray

Reputation: 1157

How to force a child class to declare a specific inner class

I'm wringing my brains to try to find a simple way to force a child class to declare another type of child class. For instance, I've got

public final class MessageType1 extends MessageType {
    public static final class Subtypes extends MessageSubtypes {
         public static int SOME_SUBTYPE = 1;
    }
}


public final class MessageType2 extends MessageType {
    public static final class Subtypes extends MessageSubtypes {
         public static int ANOTHER_SUBTYPE = 1;
    }
}

public abstract class MessageType {
    public static abstract class MessageSubtypes {
        public static int ALL_SUBTYPES = 0;
    }
}

Is there a way to ensure that every child of MessageType has to create its own version of MessageSubtypes and name it Subtypes?

Or maybe I'm spinning in the wrong circles and there's a better way to do this. Basically I'm just wanting to ensure that all of my message types have their own set of unique subtypes and that each subtype has a member called ALL whose value is 0. Creating a MessageType without a subtype should not compile, but if that's not possible it should at least not be usable, and throw an exception if it occurs.

Upvotes: 2

Views: 1686

Answers (5)

Ginger McMurray
Ginger McMurray

Reputation: 1157

I'm starting to think that I'm overthinking things and should just keep it simple. While my goal is to force everyone to have an ALL, it's possible that there might one day be a subtype that shouldn't allow subscription to all of its messages. I'm thinking of simplifying things with:

public abstract class MessageType {

    protected static class BaseMessageSubtype {
        public static int ALL = 0;
    }

}

public class OrderMessageType extends MessageType {

    public static class MessageSubtype extends BaseMessageSubtype {
        public static int SETTLED = ALL + 1;
        public static int OPENED  = ALL + 2;
        public static int CLOSED  = ALL + 3;
        public static int VOIDED  = ALL + 4;
        public static int CHANGED = ALL + 5;
    }

}

Calls would still be made using .Subtype. but if someone really wants to disallow an ALL they could. I can't enforce the need for every type to have a Subtype class, but that might not be a problem. so long as someone can eventually refer to a message type that has integer values for its subtypes we're ok. It's remotely possible that someone might override the 0 that is ALL and accidentaly get too many messages, but the project is wholly internal for now so that's not likely to happen any time soon.

Upvotes: 0

Matt Ball
Matt Ball

Reputation: 359836

How to force a child class to declare a specific inner class?

You can't.

The most you can do is declare an abstract method which the subtypes must implement. In your case, you could declare a method abstract Set<MessageSubtype> getSubtypes().


Note that I changed the name to singular. Also, you're almost certainly better off using an enum than a class for the subtypes, since enums are by far the best way to represent a fixed set of typed values which are known at compile time.


Basically I'm just wanting to ensure that all of my message types have their own set of unique subtypes and that each subtype has a member called ALL whose value is 0. Creating a MessageType without a subtype should not compile, but if that's not possible it should at least not be usable, and throw an exception if it occurs.

You're thinking too much about implementation, and not enough about the API that your code exposes. I think pretty much every intermediate-level Java programmer tries to do something like this at some point (I certainly have!). Think about providing an interface to use for consumers of your code.

Upvotes: 6

Irfy
Irfy

Reputation: 9587

Nested classes do not take part in polymorphism (just like fields don't) so that would generally be an inappropriate approach. A more dynamic language like Python may be more suited to what you are trying to achieve.

However, can you describe the functionality of these subtypes? Could it perhaps be better to define an interface/abstract class like this:

class MessageType {
    public abstract MessageSubtype[] getSubtypes(); // to enumerate them
    public instantiateSubType(<some kind of type discriminator>); // basically a factory function.
}

You may want to look at the Abstract factory pattern

Upvotes: -1

Mike Samuel
Mike Samuel

Reputation: 120516

Put a check in the base class's constructor:

class BaseClass {
  public BaseClass() {
    assert isValidSubclass() : getClass() + " does not contain a suitable inner class";
    ...
  }

  private boolean isValidSubclass() {
    Class<?> cl = getClass();
    // Maybe cache the test results in a static thread-safe table.
    for (Class<?> innerClass : cl.getDeclaredClasses()) {
      if (/* is suitable according to your criteria*/) { return true; }
    }
    return false;
  }
}

As long as you run your tests with assertions enabled, that will cause them to fail-fast the first time someone attempts to construct an instance of a subclass that does not declare a suitable inner class.

Upvotes: 1

duffymo
duffymo

Reputation: 308763

I don't think super classes can ever know if or how they'll be subclassed.

You could create an enumeration and have a get method return a value of that type. That might make clear to subclasses that they should alter the enumeration to add their own type.

The larger question is: why do you think this is necessary? Is the class name supposed to be sufficient information regarding type? And doesn't your design defeat the purpose of polymorphism and dynamic binding?

Upvotes: 1

Related Questions