-3

I have an 8-level hierarchy of classes in Java. This is useful so each abstract class implements methods that are common in the whole sub-branch of the tree. That's working fine.

However, after going back and forth with some design I realized some behavior is applied very discretionary to some leaf nodes only. There's no clear rule, that could follow the existing hierachy. I have identified these leaf classes and I wanted to understand what's the best way of implementing those, since the logic is EXACTLY the same one every time.

For example, in the simplified example below only the green leaf classes should implement the method.

example tree

If I create a separate interface with the abstract method declaration I could mark all those leaf classes to implement the method.

How can I place the logic in the new interface somehow? I don't want to copy the same code 80 times, in each affected tree class.

1
  • 4
    "I have an 8-level hierarchy of classes in Java." -- notwithstanding that you claim that is useful, this is an enormous red flag for me. In particular, if the point is inheritance of implementation (as you describe) then there's a good chance that you could achieve many of your shared-implementation goals by strategic use of composition in place of inheritance. That could well net you a significant reduction in the total number of classes, and possibly even get you DRYer code than you already have. Commented Sep 15 at 17:07

1 Answer 1

1

interfaces and default methods.

Put into an interface both the implementation of your common code as well as declaring every 'aspect' that your common code needs. For example:

/**
 * Implementations represent inventory stuff that can automatically order more inventory if it is nearly running out.
 */
public interface AutoReorder {
  int getStock();
  String getSku();

  default void reorderIfNeeded() {
    int req = InventorySystem.getMinimumStockLevel(getSku());
    int delta = req - getStock();
    if (delta > 0) {
      InventorySystem.reorder(getSku(), delta + 5);
    }
  }
}

Types that add implements AutoReorder can provide their own implementation of reorderIfNeeded but they don't have to. If they don't, they get the above implementation. Those type do have to provide implementations for getSku() and getStock().

The one thing you can't have is state. Interfaces cannot have fields or constructors. If that's what you need, you must extends it. If you can't do that because you're already extending something else, this won't work. You then:

  • Don't have a default at all, instead, have one package-private class with the impl and have each node-type that wants this feature write its own wrapper oneliner that invokes the package private helper. There is obviously no reason to actually copy/paste code, ever, of course.

  • Rewrite so you don't need the state / the implementing type manages it.

  • Have a type that encompasses the system you are modelling. For example, a class InventorySystem, and that's where the common-to-some-nodes code goes, where node types are ToiletPaper, DishwashingLiquid, etc.

Sign up to request clarification or add additional context in comments.

1 Comment

I don't need state, just the method. Let me check a bit more, but seems like this could work for me.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.