简体   繁体   中英

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.

An interface is a contract that the class which implements it agrees to fulfill.

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 .

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 .

[...] 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 .

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.

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 { ... }

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM