接口、抽象 Class 和抽象方法 Class

Interface, Abstract Class and Methods of Abstract Class

我正在学习如何使用 工厂模式 在 Java 中创建对象。我想创建 classes 来管理汽车。汽车可以是小的也可以是大的。我创建了一个接口来定义要由实现 class 实现的方法。一个abstractclass实现了一些小车和大车共享接口的常用方法。具体的 SmallCar 和 LargeCar classes 实现了抽象 class.

的剩余方法

车机界面

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

抽象汽车CLASS实现汽车接口

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;
 }
}

小车加长摘要CLASS

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

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

工厂CLASS

此 class 负责创建特定类型汽车的实例。

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;                
}

主要方法

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.

挑战在于 Car 的实例可以访问 Car 接口上定义的所有其他方法,但它不能访问在抽象 class 上定义但未在接口上定义的 isTankFull() 方法。我希望我的解释足够清楚。

你看不到方法的原因是因为你的 c 对象被声明为 Car 接口。当然,当它从您的工厂方法中出来时,它是一个 SmallCar,但是您的变量只有接口。您可以将声明更改为 AbstractCar c = CarFactory.createCar("SmallCar", regnum);.

另一种在使用界面时可以实现此目的的方法是在尝试访问不在界面上的方法时将 c 对象转换为 AbstractCar,但是您需要请小心,因为您的工厂总是有可能 return 实现 Car 的对象,而不是 AbstractCar.

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

当然,另一个简单的解决方案是将方法添加到界面中,尽管这会消除该问题的教学机会。

好的解决办法是把你的isTankFull()放在界面上。这是有道理的,因为任何实现 Car 的汽车都需要访问 isTankFull().

问题是:您是否正在创建无法回答问题 isTankFull 的任何 Car?如果是这样,那么将 isTankFull 移动到界面将没有意义。

另一种解决方案(如果您不希望您的 isTankFull() 出现在界面上),是将您的 Car 转换为适当的类型:

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

接口是您与实现它的 classes 的用户签订的合同(或协议)。所以你必须问自己 any Car 是否应该公开信息 isTankFull(即应该回复消息 isTankFull)。如果答案是'yes',则必须在接口中添加方法isTankFull

查看您的代码,class AbstractCar 似乎只是一个 实用程序 class。然后,方法isTankFull应该提升到界面,或者至少应该protected

另一方面,您必须问问自己,您的客户端代码(即 main 方法)是否真的需要通用 Car,或者它是否需要特定类型的汽车,例如 SmallCar.

最后,请记住,使用接口可以最大限度地减少组件之间的依赖性。