Полиморфизм лучшая практика - PullRequest
0 голосов
/ 29 августа 2018

Я изучал шаблоны проектирования Java, чтобы сделать свои проекты более организованными, мне нужно знать одну вещь: если следующий метод является хорошей практикой.

При использовании родительского абстрактного класса или интерфейса методы для подклассов определяются в родительском.

Моя проблема в том, что когда у меня есть куча подклассов, если каждый переопределяет метод A в родительском, но у одного из подклассов должен быть свой метод B, рекомендуется ли определять метод B в родительском классе даже если он используется только для этого подкласса.

Это ставит проблему, что methodB нужно будет использовать в каждом подклассе, даже если он никогда не вызывается из этого класса.

Должен ли я сделать это? Это не кажется правильным.

Пример кода:

public interface Parent{

  public void methodA();

  //Should this method be in the parent as it is only used once?
  public void methodB();

}

подклассы:

public class First implements Parent{

  @Override
  public void methodA(){
    System.out.println("This is method A");
  }

  // Does Nothing but java must have it used in the sub class
  @Override
  public void methodB(){
    throw new UnsupportedOperationException("Do not call methodB from class First!!");
  }
}



public class Second implements Parent{

@Override
  public void methodA(){
    System.out.println("This is method A");
  }

  // methodB is being used for this sub-class
  @Override
  public void methodB(){
    System.out.println("This is method B");  
  }

}

Как вы можете видеть из приведенного выше кода, я использую methodB только для второго подкласса, но мне все еще необходимо использовать его в первом подклассе, иначе выдается исключение. Поскольку этот метод никогда не должен вызываться внутри первого класса, я просто выбрасываю исключение с сообщением. Это кажется неорганизованным. Это определенно неправильное использование наследства.

Если я использую только methodB во втором классе, не добавляя его к родителю:

 public static void main(String[] args) {
   Parent p = new Second();
   p.methodA() // Prints "This is method A"
   p.methodB() // throws an error
 }

Кто-нибудь знает, как я могу вызвать определенный метод в классе, не выдавая ошибку. Добавление метода к родителю - определенно плохая практика.

EDIT:

Спасибо за все быстрые ответы, я обнаружил, что вместо этого можно определить разные интерфейсы:

interface X {
  public void A()
}

interface Y extends X {
  public void B()
}

class First implements X {
  @Override
  public void A();
}

class Second implements Y {
    @Override
    public void A();

    @Override
    public void B();
}

Если это все еще неправильно, пожалуйста, скажите мне.

Ответы [ 3 ]

0 голосов
/ 30 августа 2018

interface - это контракт, который класс, который его реализует, обязуется выполнить.

Рассмотрим гипотетический интерфейс под названием Furniture. Не все Furniture будут разумно реализовывать метод recline() - например, таблицу - но некоторые могут. Это хороший пример того, почему метод recline() должен быть не в этом интерфейсе, а, возможно, в расширенном интерфейсе RecliningFurniture.

Таким образом, объект класса Table будет реализовывать Furniture, но объект класса Chair может вместо этого реализовать RecliningFurniture. Оба будут связаны договором интерфейса Furniture, но Chair также должен будет выполнить дополнительные условия договора RecliningFurniture.

0 голосов
/ 30 августа 2018

если некоторые объекты ведут себя как X, а другие как X + что-то еще вам нужно 2 интерфейса, потому что у вас есть 2 вещи, где один похож на другой, плюс немного больше

interface X {
      public void A()
}

interface Y extends X {
      public void B()
}

class First implements X {
      @Override
      public void A();
}

class Second implements Y {
      @Override
      public void A();
      @Override
      public void B();
}

все будет вести себя как X в обстоятельствах, когда вам нужен X, это точно. В других вы должны упомянуть, что здесь у нас есть нечто большее

0 голосов
/ 30 августа 2018

[...] рекомендуется определить метод B в родительском объекте, даже если он используется только для этого одного подкласса.

Конечно, нет.

Представьте, как быстро ваш суперкласс будет расти, если каждый из его подклассов добавит свою часть. У каждого ребенка будет куча несвязанных вещей, которые требуются другим подклассам. Это указывает на неправильные отношения между классами и неправильное использование наследования.

В вашем фрагменте отношения между классами неясны. Наследование всегда требует реальных примеров. Здесь я не могу утверждать, что First является Parent.

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

Было бы немного лучше вашей текущей ситуации:

default void methodB() {
     throw new UnsupportedOperationException("[...]");
}

Передав экземпляр Parent методу, убедитесь, что вы будете использовать только интерфейс, предоставленный этим классом. Это удержит вас от приведения и сбивания его интерфейса.

A -> [methodA] (only)
B -> [methodB] (only)
C -> [methodA, methodB]

Если данных методов недостаточно, создайте составной интерфейс, который добавит пропущенные методы:

interface A { void methodA(); }
interface B { void methodB(); }
interface C extends A, B {}

class First implements A { ... }
class Second implements C { ... }
...