Polymorphism best practice
Polymorphism best practice
I've been investigating java design patterns to make my projects more organised, one of the things I need to know is that if the following method is good practice.
When using a parent abstract class or interface, the methods for the sub classes are defined in the parent.
My issue is that when I have a bunch of sub classes, if each overrides method A in the parent, but one of the sub classes needs to have a different method B, is it good practice to define method B in the parent, even though it is only being used for that single sub class.
This poses the issue that methodB will need to be used in every sub class even if it is never called from that class.
Am I meant to do this? It doesn't seem right.
Code Example:
public interface Parent
public void methodA();
//Should this method be in the parent as it is only used once?
public void methodB();
Sub-Classes:
public class First implements Parent
@Override
public void methodA()
System.out.println("This is method A");
// Does Nothing but java must have it used in the sub class
@Override
public void methodB()
throw new UnsupportedOperationException("Do not call methodB from class First!!");
public class Second implements Parent
@Override
public void methodA()
System.out.println("This is method A");
// methodB is being used for this sub-class
@Override
public void methodB()
System.out.println("This is method B");
As you can see from the code above, I only use methodB for the second sub-class, but I am still required to use it in the first sub-class or an exception is thrown. Since this method should never be called inside the first class I simply throw an exception with a message. This seems unoriganised. It is definitely wrong use of inheritance.
If I only use methodB in the Second class, without adding it to the parent:
public static void main(String args)
Parent p = new Second();
p.methodA() // Prints "This is method A"
p.methodB() // throws an error
Does anyone know how I can call a specific method that is in a class without throwing an error. Adding the method to the parent is definitely bad practice.
EDIT:
Thanks for all the quick responses, I discovered that the way to do this is to instead define different interfaces:
interface X
public void A()
interface Y extends X
public void B()
class First implements X
@Override
public void A();
class Second implements Y
@Override
public void A();
@Override
public void B();
If this is still incorrect, please tell me.
What do you mean a "different method B" if it's only used in a single sub-class? If it's only in a single child class, and you're overriding method A anyway, who cares what what's in the methods? If a subclass doesn't need method B why would it be in the parent?
– Dave Newton
Aug 29 at 21:05
If one of the subclasses needs a method B, then it seems to me that either method B is private to that subclass or else that subclass isn't really an instance of the interface.
– Ted Hopp
Aug 29 at 21:06
Should
First
and Second
be implementing Parent
? If so, please write that.– Andy Turner
Aug 29 at 21:18
First
Second
Parent
I'd managed to read your question to me in comments before you deleted it, and tried to answer it (updated)
– Andrew Tobilko
Aug 29 at 21:52
3 Answers
3
[...] is it good practice to define method B in the parent, even though it is only being used for that single subclass.
Of course, no.
Imagine how rapidly your superclass would be growing if each of its subclasses added own piece. Each child would have a bunch of unrelated stuff that other subclasses require. It indicates incorrect relationships between classes and the wrong usage of inheritance.
In your snippet, the relationships among the classes are obscure. Inheritance always requires real examples. Here, I can't state that First
is a Parent
.
First
Parent
For a method that is going to be implemented by almost all subclasses, I've seen a practice of defining that method within the parent with the default exception-based implementation. So you won't be needed to duplicate the standard behaviour in subclasses.
It would be a little improvement to your current situation:
default void methodB()
throw new UnsupportedOperationException("[...]");
Passing a Parent
instance to a method, make sure that you will utilise only the interface provided by this class. That would keep you away from casting and clattering up its interface.
Parent
A -> [methodA] (only)
B -> [methodB] (only)
C -> [methodA, methodB]
If the given methods are not enough, make a compound interface which will add the missed methods:
interface A void methodA();
interface B void methodB();
interface C extends A, B
class First implements A ...
class Second implements C ...
Thanks for the detailed answer with code example, makes more sense now.
– Ben Henderson
Aug 29 at 21:54
An interface
is a contract that the class which implements it agrees to fulfill.
interface
Consider a hypothetical interface called Furniture
. Not all Furniture
would reasonably implement the recline()
method - such as a table - but some might. This is a good example why the recline()
method shouldn't be in this interface, but perhaps in an extended interface RecliningFurniture
.
Furniture
Furniture
recline()
recline()
RecliningFurniture
In this way, an object of class Table
would implement Furniture
but an object of class Chair
might instead implement RecliningFurniture
. Both would be bound by the contract of the Furniture
interface, but the Chair
would also have to fulfill the additional terms of the contract RecliningFurniture
.
Table
Furniture
Chair
RecliningFurniture
Furniture
Chair
RecliningFurniture
So pretty much define different interfaces for different categories of sub-classes? This makes more sense, thanks for the answer.
– Ben Henderson
Aug 29 at 21:31
Yes, that is one way. You could also create a class which implements your interface, then extend that class into subclasses. Maybe you want an abstract Chair implements Furniture, then you create a RecliningChair and a SwivelChair, and a Stool, which all extend Chair. Just depends on your project and what you're trying to accomplish.
– Bryan
Aug 29 at 21:35
if some objects behave like X and other like X + something else you need 2 interfaces, cause you have 2 things where one is like the other one plus a bit more
interface X
public void A()
interface Y extends X
public void B()
class First implements X
@Override
public void A();
class Second implements Y
@Override
public void A();
@Override
public void B();
all will behave like X in circumstances where you need X, that's for sure. In other ones you will have to mention that here we have something more
Thanks for the answer, this makes much more sense.
– Ben Henderson
Aug 29 at 21:32
Required, but never shown
Required, but never shown
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
I guess that's a violation of the Liskov substitution principle. You shouldn't use inheritance if something isn't actually a more refined or specialized subtype and you definitely shouldn't put methods (i.e. behavior) into a parent if that's not actually behavior of all childs. Rethink those classes. (see also en.wikipedia.org/wiki/Circle-ellipse_problem)
– zapl
Aug 29 at 21:05