2015-03-09 3 views
0

Я изучаю как использовать Заводской шаблон для создания объектов в 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. 

Задача состоит в том, что экземпляр автомобиля может получить доступ к любому другому методу, определенному в интерфейсе автомобиля, но он не может получить доступ к методу isTankFull(), определенному на абстрактном классе, но не определен на интерфейсе. Надеюсь, мои объяснения достаточно ясны.

+1

Ничего странного здесь. Поместите isTankFull на интерфейс. – granadaCoder

+0

Вам нужно отдать свой экземпляр в AbstractCar – CKing

ответ

2

Причина, по которой вы не видите метод, существует потому, что ваш объект c объявлен как интерфейс Car. Конечно, когда он выходит из вашего заводского метода, это SmallCar, но ваша переменная есть только интерфейс. Вы можете либо изменить свое объявление на AbstractCar c = CarFactory.createCar("SmallCar", regnum);.

Еще один способ, которым вы могли бы выполнить это при работе с интерфейсом, - это сделать свой объект c объекту AbstractCar при попытке доступа к методам, которые не находятся на интерфейсе, однако вам нужно быть осторожными, поскольку всегда есть вероятность, что ваш завод может вернуть объект, который реализует Car, но не AbstractCar.

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

Конечно, другое простое решение было бы добавить метод к интерфейсу, хотя это устранило бы возможность преподавания от этого вопроса.

+2

Также будьте осторожны, когда вы бросаете экземпляр, возвращенный с фабрики, потому что фабрика может возвратить некоторый экземпляр Car, который не является производным от AbstractCar. – buftlica

+0

Хорошая точка. Я уточню это. Кастинг был запоздалым. – krillgar

1

Хорошим решением является надеть ваш isTankFull() на интерфейс. Это имеет смысл, поскольку любой автомобиль, реализующий Car, нуждается в доступе к isTankFull().

Вопрос: вы создаете какой-либо Car, который не сможет ответить на вопрос isTankFull? Если это так, то перемещение isTankFull на интерфейс не имеет смысла.

Другое решение (если вы не хотите, чтобы ваш isTankFull() быть на интерфейсе), чтобы отдать свой Car к соответствующему типу:

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

Интерфейс представляет собой контракт (или протокол), который вы сделали с пользователями классов, которые его реализуют. Поэтому вы должны спросить себя, если любойCar должен предоставить информацию isTankFull (т. Е. Должен отвечать на сообщение isTankFull). Если ответ «да», то к интерфейсу должен быть добавлен метод isTankFull.

Глядя на ваш код, кажется, что класс AbstractCar - это только служебная программа класс. Затем метод isTankFull должен быть поднят до интерфейса или должен быть сделан как минимум protected.

С другой стороны, вы должны спросить себя, нужен ли ваш код клиента, т. Е. Основной метод, общий номер Car, или если ему нужен конкретный вид автомобиля, например SmallCar.

Наконец, помните, что использование интерфейса позволяет минимизировать зависимость между вашими компонентами.

Смежные вопросы