#java #hashmap
#java #hashmap
Вопрос:
У меня есть 2 класса: грузовик и седан. Когда происходит какое-то действие, я хочу добавить седан в HashMap в классе Truck. Карта показывает, какие седаны в настоящее время находятся в грузовом автомобиле. Я не хочу, чтобы Truck и Sedan знали друг о друге, поэтому я создал метод в CarManager, который может вызывать Sedan, который передает идентификатор sedan и идентификатор грузовика, к которому Sedan хочет быть добавлен. Затем CarManager сообщит грузовику, что седан хочет быть добавлен в список. Проблема в том, что я не знаю, как CarManager будет информировать грузовик и что я должен иметь в этом методе addSedan. У меня есть HashMap в CarManager, который содержит коллекцию объектов. CarManager не может получить доступ к методу addCar для грузовика, поскольку его нет в интерфейсе, и я не хочу добавлять его в интерфейс, потому что не все CarEntity будут его использовать. Кто-нибудь может помочь?
public interface CarEntity {
String getId();
double getSpeed();
void move();
}
public class CarManager {
private HashMap<String, CarEntity> hash = new HashMap<String, CarEntity>();
public void addSedan(String carId, String truckId) {
???
hash.get(truckId).addCarr(carId); //I don't think this will work
}
}
public class Truck implements CarEntity {
private HashMap<String, CarEntity> cargo = new HashMap<String, CarEntity>();
public void addCar(String id, CarEntity ce) {
cargo.put(id,ce);
}
public class Sedan implements CarEntity {
CarManager.addSedan("Car 1", "Truck 5");
}
Ответ №1:
Если вы не можете использовать приведения и instanceof и должны использовать полиморфизм, добавьте два метода в свой интерфейс CarEntity :
boolean canBeLoadedWithCars();
void addCar(CarEntity c) throws IllegalStateException;
Грузовики могут быть загружены автомобилями и, таким образом, реализовать первый methof, вернув true . Другие возвращают false .
addCar
Метод Truck
добавляет car на свою карту, тогда как другие реализации выдают исключение IllegalStateException, потому что они не могут быть загружены cars .
Таким addCar
образом, метод менеджера становится
CarEntity truck = hashMap.get(truckId);
if (truck.canBeLoadedWithCars() {
truck.addCar(sedan);
}
Комментарии:
1. Но затем я сталкиваюсь с проблемой, заключающейся в том, что все службы должны будут реализовать эти методы, когда это нужно только грузовику
2. Реализация этих методов очень проста. Всего одна строка кода. Но вы могли бы наследовать реализацию по умолчанию из класса AbstractCarEntity и переопределять их только в классе Truck .
3. Но разве это не плохой дизайн — иметь некоторые методы в интерфейсе, когда его использует только один класс?
4. Нет. Это не обязательно плохой дизайн. Позже вы можете ввести трактор, который также может загружать автомобили, и ваш дизайн вообще не изменится, чего нельзя сделать при использовании instanceof и приведений. В этом прелесть полиморфизма.
5. Я понимаю. Это было мое первоначальное намерение, но разве другие классы, которые реализуют addCar, не должны быть просто пустыми
void addCar(CarEntity c) {}
? Что это за одна строка кода, на которую вы ссылаетесь?
Ответ №2:
Я думаю, одна вещь, которую вы можете сделать, это
CarEntity t = hash.get(truckId);
if (t instanceof Truck)
downcast car entity to truck
call add car method
Комментарии:
1. Я не могу это использовать. В моем случае кастинг не одобряется.
Ответ №3:
Ответ зависит от того, кто выполняет действие. Если Sedan
s добавляют себя в грузовик, у вас должен быть addTruck
метод, который добавляет все грузовики в менеджер. Менеджер сохранит Truck
s в a Map
.
private Map<String, Truck> trucks = new HashMap<String, Truck>();
public void registerTruck(Truck truck) {
trucks.put(truck.getId(), truck);
}
Тогда addCar()
метод в диспетчере будет выполнять:
public void addCar(String truckId, CarEntity car) {
Truck truck = trucks.get(truckId);
// null handling needed here
truck.addCar(car);
}
Если вместо этого грузовики забирают автомобили, тогда вы могли бы зарегистрировать автомобили вместо этого. Если вам нужно, чтобы оба были по идентификатору строки, вам нужно будет зарегистрировать как легковые, так и грузовые автомобили и сделать что-то вроде:
private Map<String, Truck> trucks = new HashMap<String, Truck>();
private Map<String, Sedan> sedans = new HashMap<String, Sedan>();
public void registerTruck(Truck truck) {
trucks.put(truck.getId(), truck);
}
public void registerSedan(Sedan sedan) {
sedans.put(sedan.getId(), sedan);
}
public void addSedan(String sedanId, String truckId) {
Sedan sedan = sedans.get(sedanId);
Truck truck = trucks.get(truckId);
// null handling needed here
truck.addCar(sedan);
}
Обычно мы используем интерфейсы Java для выполнения развязки. Truck
Класс должен иметь возможность добавлять a CarEntity
к своей загрузке, не зная, что это a Sedan
. В этом случае addCar(CarEntity car)
метод on Truck
звучит нормально. Он Sedan
никогда не узнает, что он находится на a Truck
, и все, что знает грузовик, — это методы, предоставляемые через CarEntity
интерфейс. В этом случае, возможно, менеджер уходит.
Комментарии:
1. Я все еще немного в замешательстве. Где находится хэш-карта грузовиков? В CarManager? Потому что я пытаюсь добавить седан в HashMap, который находится в классе Truck, а не в CarManager.
2. Если вы хотите ссылаться на
Sedan
s иTruck
s только как на строковые идентификаторы в диспетчере, тогда менеджеру потребуется сопоставление из truckId -> truck и sedanId ->Sedan
. В нем все еще будет коллекцияCarEntity
объектовTruck
.3. О, и вам не нужно поле id на
Truck.addCar()
. Он должен вызыватьgetId()
CarEntity
.4. Извините, я все еще немного сбит с толку. В addSedan()
truck.addCar(sedan);
это опечатка для truck? Разве это не должно бытьcargo.addCar(sedan);
в моем случае?5. Вы нашли свой ответ, но я подумал, что все равно отвечу.
addSedan()
Метод находится в диспетчере. Он находит экземпляры truck и sedan и затем вызываетtruck.addCar(sedan)
. ВнутриTruck.addCar()
метода он выполняетcargo.put(car.getId(), car)
.