вызов метода класса в Java по сравнению с Python (общий вопрос OO)

В приведенном ниже классе Java определены два метода search. Они различаются по типу searchSpec. Насколько я понимаю, когда откуда-то вызывается метод search, проверяется тип searchSpec, и в зависимости от этого типа вызывается правильный метод search.

Теперь я реализовал этот класс на Python, используя абстрактные базовые классы. И GuitarSpec, и MandolinSpec наследуются от моего абстрактного базового класса и имеют собственный метод matches. Но у меня нет возможности создать два метода search в Inventory, потому что тип аргументов не имеет значения в Python.

Это означает, что в Python при вызове метода search объекта Inventory существует вероятность того, что будет возвращен список, содержащий объекты Guitar и Mandolin. Итак, мне хотелось бы знать, как я могу получить то же преимущество проверки ввода типа Java, каким-то образом реализованного в Python, чтобы я мог гарантировать, что метод search возвращает только инструменты того же типа класса.

Это класс Java.

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

public class Inventory {

  private List inventory;

  public Inventory() {
    inventory = new LinkedList();
  }

  public void addInstrument(String serialNumber, double price,
                            InstrumentSpec spec) {
    Instrument instrument = null;
    if (spec instanceof GuitarSpec) {
      instrument = new Guitar(serialNumber, price, (GuitarSpec)spec);
    } else if (spec instanceof MandolinSpec) {
      instrument = new Mandolin(serialNumber, price, (MandolinSpec)spec);
    }
    inventory.add(instrument);
  }

  public Instrument get(String serialNumber) {
    for (Iterator i = inventory.iterator(); i.hasNext(); ) {
      Instrument instrument = (Instrument)i.next();
      if (instrument.getSerialNumber().equals(serialNumber)) {
        return instrument;
      }
    }
    return null;
  }

  public List search(GuitarSpec searchSpec) {
    List matchingGuitars = new LinkedList();
    for (Iterator i = inventory.iterator(); i.hasNext(); ) {
      Guitar guitar = (Guitar)i.next();
      if (guitar.getSpec().matches(searchSpec))
        matchingGuitars.add(guitar);
    }
    return matchingGuitars;
  }

  public List search(MandolinSpec searchSpec) {
    List matchingMandolins = new LinkedList();
    for (Iterator i = inventory.iterator(); i.hasNext(); ) {
      Mandolin mandolin = (Mandolin)i.next();
      if (mandolin.getSpec().matches(searchSpec)) 
        matchingMandolins.add(mandolin);
    }
    return matchingMandolins;
  }
}

Это класс Python.

class Inventory:
    def __init__(self):
        self.instruments: List[Union[Guitar, Mandolin]] = []

    def add_instrument(self, serial_number: str, price: float, spec: Union[GuitarSpec, MandolinSpec]):
        if isinstance(spec, GuitarSpec):
            instrument = Guitar(serial_number, price, spec)
        else:
            instrument = Mandolin(serial_number, price, spec)
        self.instruments.append(instrument)

    def get(self, serial_number) -> Union[Guitar, Mandolin, None]:
        for instrument in self.instruments:
            if instrument.serial_number == serial_number:
                return instrument
        return None

    def search(self, search_spec: Union[GuitarSpec, MandolinSpec]) -> List[Union[Guitar, Mandolin]]:
        matching_instruments = []
        for instrument in self.instruments:
            if instrument.get_spec().matches(search_spec):
                matching_instruments.append(instrument)
        return matching_instruments

person Payam Mesgari    schedule 26.02.2020    source источник


Ответы (1)


Перво-наперво: в коде Java вы используете необработанные типы, а не правильные дженерики с проверкой типов. Например,

 private List inventory;

должно быть что-то вроде

private List<? extends Instrument> inventory;

public Inventory() {
    inventory = new LinkedList<>();
}

Более того, вы также используете необработанные итераторы и в конечном итоге делаете что-то вроде этого:

Guitar guitar = (Guitar)i.next();

который просто компилируется с предупреждением, но во время выполнения выдает исключение ClassCastException. По сути, у вас та же проблема, что и с кодом Python.

После того, как вы изменили необработанные типы, один из способов отличить инструменты — отфильтровать их по типу и предикату, например. что-то вроде этого:

inventory.stream().filter(item -> item instanceof Guitar).filter(...)

В Python вы можете использовать понимание списка для фильтрации элементов.

person momo    schedule 26.02.2020