Вызов метода объекта в хэш-карте в Java

#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) .