【问题标题】:Interface, Abstract Class and Methods of Abstract Class抽象类的接口、抽象类和方法
【发布时间】:2015-03-09 14:10:32
【问题描述】:

我正在学习如何使用 工厂模式 在 Java 中创建对象。我想创建类来管理汽车。一辆车可以很小也可以很大。我创建了一个接口,它定义了实现类要实现的方法。抽象类实现了小型和大型汽车共享的接口的一些常用方法。具体的 SmallCar 和 LargeCar 类实现了抽象类的其余方法。

汽车界面

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

抽象汽车类实现汽车界面

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

小型车扩展抽象类

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

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

工厂类

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

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 接口上的所有其他方法,但它不能访问定义在抽象类上但未在接口上定义的 isTankFull() 方法。我希望我的解释足够清楚。

【问题讨论】:

  • 这里没什么奇怪的。将isTankFull放在界面上。
  • 您需要将您的实例转换为 AbstractCar

标签: java oop interface abstract-class late-binding


【解决方案1】:

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

在使用接口时实现此目的的另一种方法是在尝试访问不在接口上的方法时将c 对象转换为AbstractCar,但是您需要小心,因为总是有您的工厂可能返回一个实现 Car 的对象,但不是 AbstractCar

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

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

【讨论】:

  • 另外,当你转换从工厂返回的实例时要小心,因为工厂可能会返回一些不是从 AbstractCar 派生的 Car 实例。
  • 好点。我会澄清的。铸造它是事后的想法。
【解决方案2】:

好的解决方案是将您的isTankFull() 放在界面上。这是有道理的,因为任何实现Car 的汽车都需要访问isTankFull()

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

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

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

【讨论】:

    【解决方案3】:

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

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

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

    最后,请记住接口的使用可以让您最小化组件之间的依赖关系。

    【讨论】:

      猜你喜欢
      • 2017-02-19
      • 1970-01-01
      • 2014-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多