我正在学习如何使用工厂模式在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
}
}
FACTORY 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接口上定义的每个其他方法,但是它不能访问抽象类上定义但未在接口上定义的isTankFull()
方法。我希望我的解释足够清楚。
答案 0 :(得分:2)
您无法看到该方法的原因是您的c
对象被声明为Car
接口。当然,当它出自您的工厂方法时,它是SmallCar
,但您的变量只有接口。您可以将声明更改为AbstractCar c = CarFactory.createCar("SmallCar", regnum);
。
使用界面时可以实现此目的的另一种方法是在尝试访问不在界面上的方法时将c
对象强制转换为AbstractCar
,但是您需要小心因为你的工厂总有可能返回一个实现Car
而不是AbstractCar
的对象。
if (c instanceof AbstractCar) {
((AbstarctCar)c).isTankFull();
}
当然,另一个简单的解决方案是将方法添加到界面中,尽管这会从这个问题中消除教学机会。
答案 1 :(得分:1)
好的解决方案是将isTankFull()
放在界面上。这是有道理的,因为任何实施Car
的汽车都需要访问isTankFull()
。
问题是:您是否正在创建任何无法回答问题Car
的{{1}}?如果是这样,那么将isTankFull
移动到界面将没有意义。
另一种解决方案(如果您不希望isTankFull
出现在界面上),就是将isTankFull()
投射到相应的类型:
Car
答案 2 :(得分:1)
接口是您与实现它的类的用户签订的合同(或协议)。因此,您必须问自己任何 Car
是否应公开信息isTankFull
(即应回复消息isTankFull
)。如果答案为“是”,则必须将方法isTankFull
添加到界面中。
查看代码,似乎类AbstractCar
只是实用程序类。然后,方法isTankFull
应该提升到界面,或者至少应该protected
。
另一方面,您必须问自己,您的客户端代码(即主要方法)是否确实需要通用Car
,或者是否需要特定类型的汽车,例如SmallCar
。
最后,请注意,使用界面可以最大限度地减少组件之间的依赖关系。