Search code examples
javamultiple-inheritance

How to avoid multiple inheritance in java


I am in a situation, where I'm trying to implement a (relatively simple) abstract syntax tree. All of the nodes inherit from a type called SimpleNode containing some code to store line and column information and accepting a visitor.

Now, some of the nodes should also be nameable, while others should have a property "accessible" (eg. public or private). Some nodes should even support both interfaces.

I'd preferably implement this using virtual inheritance and write two classes NameableNode and AccessibleNode, but Java doesn't support MI.

Eg NameableNode might have field "name" and implement simple getters and setters for this field. Similarly, AccessibleNode might also have a field "accessibility" and getters/setters.

What is a good way to implement this and avoid introducing code duplication in a huge part of the code base?

Small code example:

public class SimpleNode {
    private int line = 0;
    private int column = 0;

    /* Getters and setters for line/column. */
    /* ... */
}

public class NameableNode extends SimpleNode {
    private String name = "";

    /* Getters and setters for name */
}

public class AccessibleNode extends SimpleNode {
    private boolean isPublic = false;

    /* Getters and setters for accessibility */
}

Solution

  • You're looking for composition. There are many flavors of this - I will propose one that, from my understanding of what you're trying to build, should suit your purpose.

    First, let's create some interfaces for yours Nodes:

    
    public interface Nameable {
        /* Getters and setters for name */
    }
    
    public interface Accessible {
         /* Getters and setters for accessibility */
    }
    
    

    Next, you probably don't want to repeat the same implementation for every Node, so let's create those implementations:

    
    public class NameDelegate() {
        private String name = "";
    
        /* Getters and setters for name */    
    }
    
    public class AccessDelegate() {
        private boolean isPublic = false;
    
        /* Getters and setters for accessibility */
    
    }
    

    Now, let's put everything together:

    public class SomeNodeA extends SimpleNode implements Nameable {
    
       private NameDelegate nameDelegate;
    
       public SomeNodeA(NameDelegate nameDelegate) {
          this.nameDelegate = nameDelegate;
       }
    
       @Override
       public String getName() {
           return nameDelegate.getName();
       }
    
       @Override
       public String setName(String name) {
           nameDelegate.setName(name);
       }
    }
    

    You can also have both behaviours in a single class:

    public class SomeNodeB extends SimpleNode implements Nameable, Accessible {
    
       private NameDelegate nameDelegate;
       private AccessDelegate accessDelegate;
    
       public SomeNodeB(NameDelegate nameDelegate, AccessDelegate accessDelegate) {
          this.nameDelegate = nameDelegate;
          this.accessDelegate = accessDelegate;
       }
    
       @Override
       public String getName() {
           return nameDelegate.getName();
       }
    
       @Override
       public String setName(String name) {
           nameDelegate.setName(name);
       }
    
       @Override
       public boolean getAccessibility() {
           return accessDelegate.getAccessibility();
       } 
    
        /* etc... */
    }
    

    The idea is, you can package the state and the functionality of the different "features" into individual delegates, and expose them as corresponding interfaces in your Nodes.

    Also, when operating on the Nodes, if you need to know whether a given instance of a Node supports a specific feature, you can use instanceof - e.g.:

    if (someNode instanceof Nameable) {
       // do naming stuff
    }