0

The graph below describes the hierarchy of MyClass and MyOtherClass. With Java is it possible to define a variable that can hold values that are either MyClass and MyOtherClass, i.e a variable definition that restricts values to instances that are both sub-classes of JComponent and implementations of MyInterface so that functions from JComponent and MyInterface are simultaneously available?

I realize the normal way to do this would be to create an intermediate abstract class that extends JComponent and implements MyInterface, so I am wondering if this behavior is possible without doing this.

The reason behind the strange class hierarchy is that I initially created MyAbstractClass to be used as a generic visual type and now would like to add some features to it, i.e. MyInterface, for use in other places. however I will also need to make some new classes that have the same additional features from MyInterface but are not instances of MyAbstract class. It would be nice if I didn't have to create a duplicate MyAbstractClass that extends some other intermediate class that extends Jcomponent and MyInterface.

o       JComponent
|
|\
| \
|  \
|   o   MyInterface
|   |
|   |\
|   | |
|\  | o MyClass
| | |
| o |   MyAbstractClass
| | |
| | |
| | /
| |/
| |
| o     MyOtherClass
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
jdodle
  • 141
  • 1
  • 3
  • 11
  • Composition might work better for this rather than inheritance, perhaps via the Command design pattern (which of course uses inheritance, but not at the GUI structural level) – Hovercraft Full Of Eels Jun 27 '18 at 21:37
  • You could perhaps use generics `` I'll have a think. – d.j.brown Jun 27 '18 at 21:41
  • @d.j.brown This is currently only allowed for class definitions I just want to define a variable in this way... [this thread](https://stackoverflow.com/questions/6643241/why-cant-you-have-multiple-interfaces-in-a-bounded-wildcard-generic/6643378) discusses why java doesn't have this option for wildcards – jdodle Jun 27 '18 at 21:51
  • @HovercraftFullOfEels If I understand what you are suggesting, I don't think it is possible since JComponent is not an interface. If it were, I could create a new interface that extends `JComponent` and `MyInterface` and then sub-class `MyAbstractClass` and have it just implement that new interface. Which would retain all the coded functions from `MyAbstractClass` whilst allowing functions from `MyInterface` to be implemented – jdodle Jun 27 '18 at 22:09
  • @jdodle will this variable ever change type within the instance of the class holding the association? i.e. will it switch between `MyClass` and `MyOtherClass`? – d.j.brown Jun 27 '18 at 22:18
  • I never said anything ab out "possible" but more about what I'd do. I avoid sub-classing GUI components unless necessary, and when I do subclass them, I try to make my GUI classes as "dumb" as possible so that all they do is display the state of the model and transmit the user interactions to the controller, and **that's it**. – Hovercraft Full Of Eels Jun 27 '18 at 22:24
  • @d.j.brown If I understand what you are asking then I would say no. But to clarify, the variable will strictly be used to call functions from either `JComponent` or `MyInterface` so there will be no need to cast it to any other type. However `MyClass` is really just a placeholder for a variety of classes that would extend `JComponent` and implement `MyInterface`. I was thinking this relationship would be defined for each individual `MyClass` but that isn't strictly necessary – jdodle Jun 27 '18 at 22:27

1 Answers1

1

As long as the variable remains the same type for any given instance you can use an upper-bounded Generic type for the variable and inject the object either via the constructor or mutator method.

Using your heirarchy as an example, below Foo has a variable bar of type T which is bound to be a subtype of JComponent and MyInterface in this case. Then you can construct an instance of Foo defining the concrete type. In practice, you're probably better off defining an abstract subclass of JComponent that provides the MyInterface methods. This way you wouldn't be bound by the Generic type.

Foo

public class Foo<T extends JComponent & MyInterface> {

    private T bar;

    public Foo(T bar) {
        this.bar = bar;
    }

    public void fooAction() {
        bar.interfaceMethod(); // MyInterface method
        System.out.println(bar.getWidth()); // JComponent method
    }
}

Usage

public class Main {

    public static void main(String[] args) {
        Foo<MyClass> a = new Foo<>(new MyClass());
        Foo<MyOtherClass> b = new Foo<>(new MyOtherClass());
        a.fooAction();
        b.fooAction();
    }
}

Output

MyClass
0
MyOtherClass
0

The same principle could be applied to static methods, e.g.:

public class Main {

    public static void main(String[] args) {
        staticAction(new MyClass());
        staticAction(new MyOtherClass());
    }

    public static <T extends JComponent & MyInterface> void staticAction(T bar) {
        bar.interfaceMethod();
        System.out.println(bar.getWidth());
    }
}

For completeness, the classes used in this example:

MyAbstractClass

public abstract class MyAbstractClass extends JComponent { }

MyInterface

public interface MyInterface {

    void interfaceMethod();

}

MyClass

public class MyClass extends JComponent implements MyInterface {

    @Override
    public void interfaceMethod() {
        System.out.println("MyClass");
    }
}

MyOtherClass

public class MyOtherClass extends MyAbstractClass implements MyInterface {

    @Override
    public void interfaceMethod() {
        System.out.println("MyOtherClass");
    }
}
d.j.brown
  • 1,822
  • 1
  • 12
  • 14
  • This morning I realized that this JComponent/MyInterface value only needs to be stored as a class member so the class can be templatized in this way. Which eliminates the need for the container class `Foo`. Outside of my particular implementation I believe this is a great solution. – jdodle Jun 28 '18 at 18:43