Ситуация с шаблоном проектирования интерфейса Java

Я застрял в проблеме. Моя проблема выглядит так. У меня есть надкласс Animal и два подкласса Human And Bird. У меня есть метод fly в моем суперклассе Animal, который обеспечит реализацию как для класса Human, так и для Bird на основе интерфейса Flyable.

Мой класс Animal выглядит так.

public class`Animal{

    public Flyable flyable;

    public void fly()
    {
        flyable.fly();
    } 

 } 

Человеческий класс выглядит так

class Human extends Animal {

  Flyable flyable;

  public Human()
  {
   flyable = new CantFly();
  }

}

Класс птиц выглядит так

class Bird extends Animal {

      Flyable flyable;

      public Bird()
      {
       flyable = new FlyHigh();
      }

    }

Интерфейсы ниже

public interface Flyable {
   public void fly();
}

public class CantFly implements Flyable{

    @Override
    public void fly()
    {
    Sysout("cant fly");
    }

Когда я звоню

Animal me = new Human();
me.fly();

Это дает мне NullPointerException

Что я здесь упускаю?.
Я предполагал. Поскольку я вызываю new Human(), он инициализирует интерфейс Flyable в суперклассе Animal. Я ошибся?

Я решил эту проблему, изменив дизайн метода.
fly(Flyable flyable). Так что мне не нужно такое дизайнерское решение. Я помню, как столкнулся с этой проблемой, когда реализовывал алгоритм поиска для приложения, которое будет предоставлять список результатов, но элемент списка будет иметь другой
пользовательский интерфейс,
HTTP-вызовы для разных конечных URL-адресов,
анализ JSON,< br> Сопоставление с различными классами POJO.
К сожалению, мне пришлось решать эту проблему с помощью альтернативного подхода, о котором я упоминал.


person Rohit Singh    schedule 12.08.2017    source источник
comment
Почему у вас есть поле flyable в родительских и подклассах? Какой смысл в дублировании?   -  person Tom    schedule 12.08.2017
comment
В суперклассе вызвать метод интерфейса Flyable. И в подклассе инициализировать летающий . Вы считаете это неправильным подходом?   -  person Rohit Singh    schedule 12.08.2017
comment
Да, это неправильно. Если вам нужно поле в родительском классе, передайте инициализацию этому классу (например, super(new CantFly());).   -  person Tom    schedule 12.08.2017
comment
Но мой SuperClass не имеет никаких параметров в конструкторе.   -  person Rohit Singh    schedule 12.08.2017
comment
И я думаю, что супер(что-то) подход потерпит неудачу, когда ваш суперкласс является абстрактным классом   -  person Rohit Singh    schedule 12.08.2017


Ответы (1)


Human наследуется от Animal, поэтому все его поля неявно "скопированы" из Animal. Поэтому вам не нужно повторно объявлять flyable в Human и Bird.

Но вы сделали. Это приводит к тому, что новые поля flyable в подклассах скрывают исходное поле, объявленное в Animal. Как следствие, когда вы делаете:

flyable = new CantFly();

в Human вы присваиваете значение flyable в Human, а не flyable в Animal.

Затем вы сделали это:

Animal me = new Human();
me.fly();

fly в Animal использует поле flyable, объявленное в классе Animal, которое еще не назначено (вы только назначили flyable в Human)! В результате возникает NPE.

Чтобы это исправить, просто удалите все поля flyable в подклассах Animal. Таким образом, остается только одно flyable поле.

Примечание

Я думаю, что этот дизайн немного странным. Human не может летать, поэтому в нем не должно быть поля flyable. На самом деле ничего не должно иметь поле flyable. Среди этих трех классов только Bird должен реализовывать Flyable.

person Sweeper    schedule 12.08.2017
comment
Вы предлагаете даже суперклассу не иметь интерфейса Flyable? - person Rohit Singh; 12.08.2017
comment
@RohitSingh Animal не должен реализовывать Flyable, потому что не все животные умеют летать. - person Sweeper; 12.08.2017
comment
Но что, если в будущем я решу ввести класс FlyWithJetPack, который будет реализовывать интерфейс Flyable. ? - person Rohit Singh; 12.08.2017
comment
Вы, кажется, неправильно поняли идею реализации интерфейса. Вы не создаете много конкретных классов, таких как FlyHigh или CantFly, и не имеете их экземпляров в виде полей Human и Bird. Bird должен непосредственно реализовывать Flyable. Human должно иметь поле с именем jetpack типа Jetpack. И Jetpack должен реализовать Flyable. Нет необходимости в классе FlyWithJetpack. @RohitSingh - person Sweeper; 12.08.2017