Принцип подстановки Лисков для разных типов данных

У меня проблема с LSP в моей программе. У меня есть абстрактный базовый класс и два разных типа продуктов: один Food , другой - электронное устройство. Мне нужно создать метод, который возвращает дату истечения/гарантию для этих продуктов. Проблема в том, что один имеет тип Date, а другой (гарантия) — тип Int... У вас есть идеи, как создать метод, удовлетворяющий обоим этим типам данных? без использования операторов switch/if, так как это нарушит OCP.

private static void printExpirationDateStatistics(List<Product> foodProducts) {
for (Product product : foodProducts) {
  System.out.println(product.getExpirationDate());
}

}

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

Это методы из базового класса

    public Date getExpirationDate() {
    return expirationDate;
  }

  public void setExpirationDate(Date expirationDate) {
    this.expirationDate = expirationDate;
  }

  public int getWarranty() {
    return warranty;
  }

  public void setWarranty(int warranty) {
    this.warranty = warranty;
  }

Пробовал сделать один метод getValidity, но проблема в том, что для еды он должен возвращать Date, а для электроники должен возвращать Int. Любые идеи ?


person SCBbestof    schedule 15.03.2014    source источник
comment
Это никак не связано с заменой Лискова. Проблема не в том, что подтип не имеет свойства базового типа, а в том, что у вас есть два разных оператора, с которыми у вас возникают проблемы при работе с ними в целом.   -  person Mike Samuel    schedule 15.03.2014


Ответы (1)


Проблема, с которой вы сталкиваетесь здесь, заключается в том, что вы хотите абстрагироваться от двух видов общей информации об истечении срока действия. Проблема в том, что эта абстракция неизвестна коду, она пока присутствует только в вашей голове :)

В настоящее время он реализован в двух вариантах: целые числа и даты (хотя я понятия не имею, что это за целое число? Это год? ... количество победителей лотереи с 1990 года? Я не знаю).

Я бы предложил добавить новый Interface для этой абстракции, например.

public interface Expiration<T> {
    T getExpiration();
}

В этом случае ваши два базовых класса могут реализовать Expiration<Date> и Expiration<Integer>, и вы можете основывать на этом свою логику проверки. Например, как:

 public boolean isValid(Expiration<Date> potentialyExpired) {
     final Date expirationDate = potentialyExpired.getExpiration();
     final Date now = new Date();
     return expirationDate.before(now);
 }

Однако это можно сделать только тогда, когда вы можете получить доступ к рассматриваемым классам. Достаточно ли этой абстракции или вам нужно еще больше?

Вы можете захотеть абстрагироваться от другого типа Expiration таким образом, чтобы вам не нужно было иметь их обоих и унифицировать их в какой-то момент. Но чтобы решать такие вещи, нужно больше знать о значении другого типа (Integer).

person tilois    schedule 15.03.2014
comment
Целое число для гарантии, оно измеряется в годах, извините, что не упомянул об этом. Я попробую вашу идею и отпишусь. Спасибо! - person SCBbestof; 15.03.2014
comment
Если он указан в годах и вы знаете дату начала действия этой гарантии, вы можете унифицировать ее до Date и рассчитать дату истечения срока действия. Это позволит избавиться от различных типов, с которыми вам в настоящее время приходится иметь дело. - person tilois; 15.03.2014
comment
На самом деле это работает, реализуя интерфейс в моих классах и переопределяя метод getExpiration(). я просто звоню: public Integer getExpiration(){ return Warranty; } или public Date getExpiration(){ return expireDate; } хD - person SCBbestof; 15.03.2014