Let's say I've got a generic java class Filter<InputType, OutputType>
which receives an input object and transforms it to an output object.
Now I've got two other classes (NoInputFilter<OutputType>
, NoOutputFilter<InputType>
) which should do the same except they haven't an InputType
respectively an OutputType
.
Now the three classes have some functionality in common. The Filter
class should handle the input object the same way like the NoOutputFilter
does, and it should handle the output object the same way like the NoInputFilter
does.
So I've got something like this in terms of functionality, where B is Filter
:
Now, Java doesn't allow to inherit from multiple classes. Is there a design pattern to do something like this?
My first approach was to have two interfaces. One interface for the input, one interface for the output. The Filter
class implements both. But this way I have to implement the interfaces two times each.
Then I thought about to give the Filter
class (which implements the two interfaces) instances of NoOutputFilter
and NoInputFilter
and just call the right method instead of have duplicated code. But this breaks the semantics, has a lot of boilerplate code, and isn't a very clean approach in my opinion. Here a little demonstration:
class Filter<InputType, OutputType> implements INoOutputFilter<InputType>, INoInputFilter<OutputType> {
private final INoOutputFilter<InputType> noOutputFilter;
private final INoInputFilter<OutputType> noInputFilter;
public void InputType setInput(InputType input) {
noOutputFilter.setInput(input);
}
public OutputType getOutput() {
noInputFilter.getOutput();
}
[...]
}
The last idea was to turn the class hierarchy up site down:
public class Filter<InputType, OutputType>
public class NoInputFilter<OutputType> extends Filter <Void, OutputType>
public class NoOutputFilter<InputType> extends Filter <InputType, Void>
This way, the classes behaves the right way, no duplicated code, but e.g. the NoOutputFilter has a public Void getOutput()
method. Even though you can not instantiate something from Void
, the API of those two classes are wrong. This would be something like this:
So this isn't a nice approach as well.
Do you have any hint how I could solve this in Java? Is there a design pattern for this?
3 Answers 3
First of all, Java 8 introduced Default Methods, which is in fact multi-inheritance in Java.
History showed that complicated inheritance structure is cancer. You should favor composition over inheritance. In this case you are mixing input filter with output filter to create artificial bi-directional filter parent. Not clean for me at all.
I don't have your full picture, but from what you described, I would consider two interfaces: InputFilter
and OutputFilter
. Eventual Bi-directional filter implementation would implement both interfaces.
And if there would be some common functionality, I would extract that common logic into separate class and use it as dependency.
-
I'm new to Java 8 but I us it already. So Default Methods sounds great and the right thing for my problem. Although I should rethink about composition. Maybe it has more benefits for me than I thought. Thank you!Obenland– Obenland2015年09月19日 19:58:51 +00:00Commented Sep 19, 2015 at 19:58
-
1From its beginning Java has made illegal multiple inheritance due to the troubles it causes; in fact it is very cleary stated that default methods introduction is only as a "last-measure" to introduce new logic into old API interfaces. Telling anyone "if you want multi-inheritance use default methods" is very bad advice.SJuan76– SJuan762015年09月19日 20:23:29 +00:00Commented Sep 19, 2015 at 20:23
-
1@SJuan76 You probably didn't read my answer, because I corrected him about non-existence of multi-inheriantce in Java, but at the same time suggested to consider composition over inheritance.luboskrnac– luboskrnac2015年09月19日 20:26:25 +00:00Commented Sep 19, 2015 at 20:26
-
@SJuan76 Thanks for stating the correct idea/usage of Default Methods. You are right, it shouldn't be used here. So I gonna use composition pattern like you and luboskrnac said.Obenland– Obenland2015年09月19日 22:01:16 +00:00Commented Sep 19, 2015 at 22:01
-
1Java always had multiple inheritance of type (via
interfaces
). With introduction ofdefault methods
(to implementfunctional interfaces
) it added multiple inheritance of behavior. It never had and will never have multiple inheritance of state.PM 77-1– PM 77-12015年09月19日 23:01:11 +00:00Commented Sep 19, 2015 at 23:01
I think your approach is wrong. You are looking at it in terms of classes instead of results. What you - in my opinion - should do is something like this:
- Define an input interface
- Define an output interface
- Define a base class implementing both, with nullable protected properties
- Define a concrete class for NoInput that exposes the output stuff
- Define a concrete class for Filter that exposes both.
That's it.
A
-
Sounds like composition, right?Obenland– Obenland2015年09月19日 19:51:18 +00:00Commented Sep 19, 2015 at 19:51
-
Mmmmmmh... you can use composition if you want, i.e. use one class for input, one for output and then a holder class with nullable properties. That is, in a way, probably better but it always depends on the use case. Interfaces are mostly a good thing if you think that one day you will have wildly different things connected to each other by some form of contract. Otherwise, they are just a check box item. I did suggest the interfaces because I think that it is likely that he/she will have this need at some point, just not now.Andrea Raimondi– Andrea Raimondi2015年09月19日 19:56:52 +00:00Commented Sep 19, 2015 at 19:56
-
At this point in time, he can well do with a base class and refactor later if needed. But that's why I suggested the interfaces: so that if/when a need arises to do that, he's all setup already.Andrea Raimondi– Andrea Raimondi2015年09月19日 19:57:39 +00:00Commented Sep 19, 2015 at 19:57
Have you considered this?
public interface Input<InputType> { ... }
public interface Output<OutputType> { ... }
public interface Filter<InputType,OutputType>
extends Input<InputType>, Output<OutputType> { }
To give a more general-purpose answer to your question:
Multi-inheritance in Java
(Please note that this is somewhat experimental, and I have not ran it by other experienced java developers to see what they think about it. Perhaps I will receive some feedback here.)
The way to achieve multi-inheritance in Java is by means of interfaces. If you have class A extending classes X and Y then you need to begin by defining interfaces for X and Y, so that A can implement both interfaces. The question now becomes, once you have all this in place, how can you avoid code duplication. Prior to Java 8, this was a mess. With Java 8, this becomes considerably easier and cleaner. (Still not as clean as I would like it to be, but at least manageable.)
Whenever I create an interface in Java 8 which is bound to be implemented in various different ways, I add Decorator
and Defaults
sub-interfaces to it. So, I build something like this:
public interface Zork
{
boolean foo();
boolean bar( int a );
interface Defaults extends Zork
{
@Override
default boolean foo()
{
return bar( 0 );
}
}
interface Decorator extends Defaults
{
Zork getDecoratedZork();
@Override
default boolean bar( int a )
{
Zork decoree = getDecoratedZork();
return decoree.bar( a );
}
}
}
This way:
A class wishing to provide an implementation of Zork can be declared with
implements Zork.Defaults
and refrain from having to implement methods for which defaults have been provided.A class wishing to act as a decorator of Zork can be declared with
implements Zork.Decorator
, supply an implementation for thegetDecoratedZork()
, and implement whatever subset ofZork
is necessary, allowing the rest of the methods to be delegated to the decoratedZork
.A class wishing to multiply inherit Zork can be declared as follows:
(Note that since Zork is an interface, the MultipleInheritor class can implement many other interfaces like Zork.)
public class MultipleInheritor implements Zork.Decorator
{
private final Zork myZork = new Zork.Defaults()
{
@Override
public boolean bar( int a )
{
return a % 2 == 0;
}
}
@Override
public Zork getDecoratedZork()
{
return myZork;
}
}
-
Why don't you add the default-methods directly to the base-interface? Is there any advantage I overlooked in the added verbosity and the extra-interface?Deduplicator– Deduplicator2015年09月20日 17:06:25 +00:00Commented Sep 20, 2015 at 17:06
-
@Deduplicator I do not remember right now the major reason why I do it. If and when I remember, I will add a comment here. In the mean time, one reason (which is probably not the main reason) is because in theory, an implementor which needs to override all methods may mistakenly omit overriding one of them, and never find out, because a default was provided. By not including default methods in the base interface I reserve the option of implementing the interface in its pure form, and if I ever forget to implement one of the methods, I will be told so by the compiler.Mike Nakis– Mike Nakis2015年09月20日 17:23:39 +00:00Commented Sep 20, 2015 at 17:23
-
@Deduplicator An example of an implementor which may need to override all methods is the decorator, though in practice I have all of my decorators extend the
Defaults
interface.Mike Nakis– Mike Nakis2015年09月20日 17:25:39 +00:00Commented Sep 20, 2015 at 17:25
Explore related questions
See similar questions with these tags.
INoOutputFilter
would becomeInputFilter
. Then theNoOutputFilter
class would implement onlyInputFilter