Search code examples
javaoopinterfaceabstract-classlate-binding

Interface, Abstract Class and Methods of Abstract Class


I am learning how to use the Factory pattern for creating objects in Java. I want to create classes to manage Cars. A car can either be small or large. I created an interface that defines the methods to be implemented by an implementing class. An abstract class implements some of the common methods of the interface shared by small and large cars. The concrete SmallCar and LargeCar classes implement the remaining methods of the abstract class.

THE CAR INTERFACE

public interface Car {
 String getRegistrationNumber();
 void drive();
}

THE ABSTRACT CAR CLASS IMPLEMENTS CAR INTERFACE

public abstract class AbstractCar implements Car { 
 private final RegistrationNumber regNumber;
 private boolean tankFull = true;

 public AbstractCar(RegistrationNumber regNumber) {
  this.regNumber = regNumber;
 }

 @Override
 public final String getregistrationNumber() {
  return regNumber.toString();
 }

/**This method is not defined in the implemented Car interface. I added it to
*the abstract class because I want subclasses of these abstract class
*to have this method*/
 public boolean isTankFull() {
  return tankFull;
 }
}

SMALL CAR EXTENDS ABSTRACT CLASS

public final class SmallCar extends AbstractCar {
 public SmallCar(RegistrationNumber regNum) {
  super(regNum);
 }

 @Override
 public void drive() {
  //implemented here
 }
}

FACTORY CLASS:

This class is responsible for creating instances of a particular type of car.

public final class CarFactory {
 public static Car createCar(String carType, RegistrationNumber regNum) {
  Car car = null;
  if (carType.equals("Small") {
   car = new SmallCar(regNum);
  }
  return car;                
}

MAIN METHOD

RegistrationNumber regNum = new RegistrationNumber('a', 1234);
Car c = CarFactory.createCar("Small", regNum);

c.getRegistrationNumber(); //this works
c.isTankFull(); //this instance of Car cannot access the isTankFull method defined on the abstract class. The method is not defined on the Car interface though. I do not understand why.

The challenge is that the instance of Car can access every other method defined on the Car interface but it cannot access the isTankFull() method defined on the abstract class but not defined on the interface. I hope my explanation is clear enough.


Solution

  • The reason why you can't see the method there is because your c object is declared as a Car interface. Granted, when it comes out of your factory method, it is a SmallCar, but your variable there is only the interface. You could either change your declaration to AbstractCar c = CarFactory.createCar("SmallCar", regnum);.

    Another way you could accomplish this while working with the interface would be to cast your c object to an AbstractCar when trying to access methods that are not on the interface, however you need to be careful as there is always the possibility that your factory could return an object that implements Car, but not AbstractCar.

    if (c instanceof AbstractCar) {
        ((AbstarctCar)c).isTankFull();
    }
    

    Of course, the other easy solution would be to add the method to the interface, though that would remove the teaching opportunity from this question.