1

I have this Java code:

public interface User{
     public void in(Message message);
}

public interface Message{
//....
}

public interface WebsiteMessage extends Message{
//....
}

public class WesiteUser implements User{
     @Override
     //I'm not allowed to do this
     public void in(WebsiteMessage message){}
}

Is there a way I can implement the in method with WebsiteMessage parameter? For the moment I'm doing something like this:

@Override
public void in(Message message){
     WebsiteMessage msg= (WebsiteMessage) message;
     //..
}
3
  • 5
    Are you allowed to modify User ? Commented Aug 17, 2016 at 8:02
  • @Spotted yes. I already selected an answer. But you can provide one if I can't modify the User and I'll up vote it Commented Aug 17, 2016 at 8:35
  • If you can't modify User I don't see any simple solution. However, I think that your current design is flawed if you need a WebsiteMessage (instead of Message) in WebsiteUser. It indicates that your interface is leaky and I'll start by reworking Message so that every User's implementations can work with a Message. Commented Aug 17, 2016 at 8:41

2 Answers 2

5

You can do it with a bounded type parameter:

public interface User<M extends Message> {
     public void in(M message);
}

public class WebsiteUser implements User<WebsiteMessage> {
     @Override
     public void in(WebsiteMessage message) {}
}
Sign up to request clarification or add additional context in comments.

6 Comments

That's the answer I was thinking of, but only doable if User can be modified, as someone asked in the comments.
@RayO'Kalahjan Well of course, but I see no indication in the question that it can't be.
Of course, I just mentioned it because I saw the question in the comments. This is the only correct answer I can think of.
thanks. that's exactly what I was looking for. yes I can edit User interface. was there other workarounds if I couldn't edit User?
The interesting part here: the original code is (imho) a violation of the Liskov substitution principle - you should not restrict the parameter types in sub classes. Wondering that your solution is at least accepted by the compiler.
|
3

Just to give a different perspective: the Liskov Substitution Principle basically tells you ... to not do that.

The idea of that principle is that in order to be sound, you should be able to replace any usage of the "base" type with the "derived" type. And that doesn't work if you restrict parameters of methods. Because when calling the method on the base class, you are allowed to use the "wider" type; which gives you an error when you try it on the derived class.

It is fine to restrict the return type; or to widen method parameters; but not the other way round.

And if you turn here you find people arguing if LSP also applies when talking about interfaces.

Long story short: even when the solution proposed by shmosel works; you might want to step back and consider if that is really the best way to solve your problem. You see, sound OO design and inheritance is more than just putting extends here or there.

5 Comments

Agree. Funny that you posted an answer related to my comment just 5 seconds later. :-)
You are welcome. Sorry for sneaking into your head and stealing that idea. But I do everything I can to pimp my reputation. Seriously: I am actually glad that I am not the only one pointing out the (at least theoretical) problem with this question and the accepted answer.
No offense (plus you're advocating in favor of clean code).
Interesting thought. But I think it depends whether you're expecting to use the User interface directly, or if it's just to establish a standard template for various distinct types. Java's Consumer, for example, "violates" LSP by your definition, but it was never intended for use without a specific type parameter.
Also note this wikipedia article which uses what's essentially my solution as an example of preserving LSP despite the use of covariant arguments. Though perhaps that's because the same class that produces T consumes it. Interpret it as you wish.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.