1

I have an abstract class A and classes B and C. Classes B and C extend A. I need to hold B and C in the list together, say List. However, B and C have unique methods, so not all items in List can be used to invoke certain methods unless I am downcasting which is considered to be a design smell.

I need to keep B and C on the same list because I want to sort them based on their shared attributes which I can. Is keeping them on the same list of their parent type and then downcasting a bad design in this situation?

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • 3
    Since you need a mixed list, you don't really have a choice. – Andreas Apr 24 '20 at 08:24
  • 1
    Yes, it's a design smell, but not every code smell equals to bad code as long as you can find good arguments to support your decision over other alternatives. – SME_Dev Apr 24 '20 at 10:30

1 Answers1

1

I need to keep B and C on the same list because I want to sort them based on their shared attributes which I can.

As long as the requirement is to keep the list sorted with mixed types B, C both extending A an to call their non-inherited methods, you have no choice than using the List<A> containing all types.

Although I also try to avoid downcasting when possible, it doesn't mean there are situations when it is neither useful nor necessary.

for (A item: sortedList) {
    if (item instanceof B) {
        Whatever fieldB = ((B) item).getFieldB();  // using non-inherited method of B
    } else if (item instanceof C) {
         Whatever fieldC = ((C) item).getFieldC();  // using non-inherited method of C
    } else {
         // either only A or anything different that extends A
    }
}

As of Java 14 thanks to JEP 305: Pattern Matching for instanceof, such thing gets less verbose:

for (A item: sortedList) {
    if (item instanceof B b) {
        Whatever fieldB = b.getFieldB();  // using non-inherited method of B
    } else if (item instanceof C c) {
        Whatever fieldC = c.getFieldC();  // using non-inherited method of C
    } else {
        // either only A or anything different that extends A
    }
}
Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • May want to make it explicit that pattern matching is currently a [preview feature](https://openjdk.java.net/jeps/12) and requires the `--enable-preview` switch to use. – Slaw Apr 24 '20 at 10:57
  • I'm sorry, what? – Slaw Apr 24 '20 at 23:20