Как добавить недостающие методы в классы в иерархии типов, чтобы обеспечить равномерную обработку? - PullRequest
0 голосов
/ 28 марта 2020

Я использую Java 8 / Java 11. У меня есть иерархия типов (в основном dtos или Java Beans), например

public abstract class Animal {
  public abstract String getName();
  public abstract int getAge();
}

И некоторые реализации, предоставляющие дополнительные свойства:

public class Dog extends Animal {

  // implementation of abstract methods from base class animal

  // additional properties
  public String getSound() {
    return "woof";
  }
}

public class Dog extends Animal {

  // implementation of abstract methods from base class animal

  // additional properties
  public String getSound() {
    return "miaow";
  }
}

public class Fish extends Animal {
  // implementation of abstract methods from base class animal

  // no implementaion for "getSound()"
}

Теперь я хотел бы обработать Collection из Animal с единообразным способом, например

animals.forEach(x -> {
  System.out.println(x.getName());  // works
  System.out.println(x.getSound();  // doesn't work, as Fish is missing the method
});

Мне было интересно, что было бы хорошим способом реализовать «отсутствующие» методы, предполагая, что они должны возвращать значение по умолчанию, например «n / a», для String.

Один очевидный способ - переместить все отсутствующие методы в базовый класс и объявить они абстрагируют или обеспечивают реализацию по умолчанию. Но я бы хотел, чтобы они были более отдельными, то есть чтобы было понятно, какие свойства были добавлены для «равномерной обработки». Другой способ - ввести вспомогательный класс, используя instance of, чтобы определить, отсутствует ли метод:

public class AnimalHelper {

  public static String getSoundOrDefault(Animal animal) {
    if (animal instanceof Dog) {
        return ((Dog)animal).getSound();
    }

    if (animal instanceof Cat) {
        return ((Cat)animal).getSound();
    }
    return "n/a";
  }
}

, который затем вызывается с Animal:

System.out.println(AnimalHelper.getSoundOrDefault(animal));

Это работает, но теперь вызывающая сторона должна определить, какие методы вызывать на Animal напрямую и для каких методов использовать помощника.

Другое решение: я предложил добавить интерфейс AnimalAdapter с использованием Java 8 особенность реализации по умолчанию:

public interface AnimalAdapter {

  default String getSoundOrDefault() {
    return "n/a";
  }
}

И добавление ее в класс Animal:

public abstract class Animal implements AnimalAdapter {
...

, что приводит к добавлению метода getSoundOrDefault() в Dog и Cat, но не Fish:

public class Dog extends Animal {
  ...
  @Override
  public String getSoundOrDefault() {
    return getSound();
  }
}

(аналогично Cat).

Любые комментарии по вышеуказанным соображениям или другие идеи будут высоко оценены.

1 Ответ

0 голосов
/ 28 марта 2020

Все, что вы упомянули как решения, действительно хорошо. Но я использую преимущество, чтобы добавить еще одно решение, основанное на технике полиморфизма c, и я думаю, что оно более простое и менее затратное с точки зрения кода. Просто я собираюсь использовать метод Object.toString () для отображения всех необходимых параметров, поэтому в первую очередь вам необходимо использовать метод @Override toString () следующим образом:

  public class Dog extends Animal {

      // implementation of abstract methods from base class animal

      // additional properties
      public String getSound() {
        return "woof";
      }

       @Override
       public String toString() {
        return getName() + "\n" + getSound();
       }
  }

  public class Fish extends Animal {

      // implementation of abstract methods from base class animal

      // no implementaion for "getSound()"

      @Override
      public String toString() {
        return getName() + "\n" + "n/a";
      }
  }

  public class Main {

     public static void main(String[] args) {
       Collection<Animal> animals = new ArrayList<>(2);
       animals.add(new Dog());
       animals.add(new Fish());
       animals.forEach(System.out::println);
    }
 }

И вот результат:

enter image description here

...