Отключение унаследованного метода в производном классе - PullRequest
28 голосов
/ 30 марта 2011

Есть ли способ, в производном от Java классе, "отключить" метод и / или поле, которое иначе унаследовано от базового класса?

Например, скажем, у вас есть базовый класс Shape с методом rotate(). У вас также есть различные типы, полученные из класса Shape: Square, Circle, UpwardArrow и т. Д.

Shape имеет метод rotate(). Но я не хочу, чтобы rotate() был доступен пользователям Circle, потому что это бессмысленно, или пользователям UpwardArrow, потому что я не хочу, чтобы UpwardArrow мог вращаться.

Ответы [ 10 ]

39 голосов
/ 30 марта 2011

Я не думаю, что это возможно.Однако вы можете дополнительно уточнить класс Shape с помощью , удалив метод rotate () из его спецификации, и вместо этого определить другой подкласс Shape с именем RotatableShape и пусть Круг извлекает из Форма и все другие Поворотные классы из RotatableShape .

Например:

public class Shape{
 //all the generic methods except rotate()
}

public class RotatableShape extends Shape{

 public void rotate(){
    //Some Code here...
 }
}

public class Circle extends Shape{
 //Your implementation specific to Circle
}

public class Rectangle extends RotatableShape{
 //Your implementation specific to Rectangle
}
17 голосов
/ 30 марта 2011

Вы можете переопределить определенный метод "rotate ()" в классе, для которого вы хотите отключить эту операцию, например,

public void rotate() {
    throw new UnsupportedOperationException();
}
5 голосов
/ 22 ноября 2015

У вас плохая иерархия классов, если вам нужно отключить методы в дочерних классах. Любой подкласс должен уметь беспрепятственно использовать методы своих суперклассов. Это называется «принцип подстановки Лискова» (https://en.wikipedia.org/wiki/Liskov_substitution_principle). Подробнее об этом можно прочитать в этой теме: https://softwareengineering.stackexchange.com/questions/219543/should-a-class-know-about-its-subclasses.

Делай, что предлагает Чанду. Не помещайте rotate () в Shape. Вместо этого создайте подкласс Shape с именем RotatableShape и поместите в него rotate (). Тогда Circle может наследовать от Shape, а Rectangle может наследовать от RotatableShape.

4 голосов
/ 30 марта 2011

Нет.

  • Вы можете использовать метод только в классе Circle (или в интерфейсе, который реализуется только этим классом)
  • Вы можете предоставить пустые реализации или те, которые бросают UnsupportedOperationException в классы, которые не поддерживают его.
3 голосов
/ 30 марта 2011

Можете ли вы использовать метод empy (ничего не делает) для круга? Для стрелки я бы пересмотрел иерархию объектов

3 голосов
/ 30 марта 2011

Объявление той же функции в дочернем классе перезапишет функцию по умолчанию, объявленную в базовом классе.Итак, в вашем дочернем классе создайте функцию с именем rotate(), которая ничего не делает, которая перезапишет поведение по умолчанию

2 голосов
/ 30 марта 2011

Один из способов справиться с этим - определить второй метод, называемый (скажем) boolean isRotatable(), и использовать его, чтобы определить, доступны ли пользователю элементы управления вращением.

Другой вариант - ввести интерфейс Rotatable и использовать shape instanceof Rotatable для определения. (Тем не менее, я думаю, что isRotatable() подход более гибкий.)

В любом случае вы можете реализовать метод rotate() для класса, который никогда не должен поворачиваться как:

public void rotate() {
    throw new UnsupportedOperationException("rotate");
}

Язык Java не предоставляет способ «удалить» или «отключить» метод в подклассе. Это нарушило бы принцип замещаемости и нарушило бы полиморфизм. Подкласс не может удалить видимые элементы из API родительских классов.

1 голос
/ 28 января 2014

Так что здесь есть две возможности. Во-первых, у вас есть объект, который может вращаться, но не показывает никаких изменений в процессе. Другой - у вас есть объект, который определяется его направлением. Каждый должен обрабатываться отдельно и по-своему.

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

В моем случае я определяю точку в трехмерном пространстве, наследуя операции от класса, определяющего кватернион. Трехмерная точка использует только 3 мнимые координаты кватерниона, и если кватернион имеет ненулевое значение для реального компонента, он разрушит жизненно важные операции алгоритма рендеринга, унаследованного от кватерниона через 3-мерную координату.

Извините, что я чрезмерно философский, однако, этот вопрос поднимает в CS вопрос о том, как с этим обращаться. Как отмечает Стивен, возможность скрывать, отключать или удалять унаследованную функцию в дочернем классе «... нарушит принцип замещаемости и нарушит полиморфизм».

Мой случай подпадает под стрелку вверх, за исключением того, что я указываю на воображение. Я пытаюсь усечь производный класс, что означает, что любой класс «внука» (возможно, наследующий операторы вращения) больше не обязательно будет кватернионом. Было бы более элегантно избегать использования исключений, обрезая базовый класс на типе для усеченного производного класса. Альтернативой было бы определение трехмерной координаты как отдельного класса с переменной кватерниона; недостаток в том, что в реализации слишком много клея.

Затем я могу поместить новые операции вращения в производный класс для трехмерных координат для трех плоскостей (ij, jk, ik), а затем объекты с 3d-вершинами можно вращать с помощью цикла и идентичного вызова функции-члена для каждой вершины. Вы можете самостоятельно отслеживать симметрию, прежде чем начнете вращать точки, определяющие поверхность сферы, поэтому вам нужно использовать функцию-заглушку и, возможно, реализовать свой собственный флаг «константа».

1 голос
/ 30 марта 2011

Я не думаю, что вы можете отключить метод так, как вы предлагаете.

В вашем примере предположим, что у вас есть метод, который принимает Shape

public void handleShape(Shape s){
  s.rotate();
}

Затем вы передаете Круг этому методу

handleShape(new Circle());

Что должно произойти? По сути, вы просите фундаментальных изменений в системе типов Java.

Если Circle является Shape и не должен вращаться, то это, вероятно, означает, что Shape был спроектирован плохо и не должен иметь метод поворота. Вы можете добавить вращение в другой класс в иерархии, например, RotatableShape или, возможно, использовать интерфейс Rotatable.

0 голосов
/ 16 июня 2018

Мне нужно было то же самое для настраиваемого алерта. Мне нужно было передать аргумент, который стал доступен только в момент показа, поэтому я реализовал свой метод show (аргумент), но show () тоже работал из-за суперкласса. Был риск того, что я мог бы вызвать myDlg.show() случайно, без аргументов, и это могло бы привести к сбою. Чтобы убедиться, что метод суперкласса никогда не вызывается вне моего класса CustomAlertDialog, я добавил к нему метод private static void show(){}. Вот и все.

Итак, чтобы отключить суперметод, сделайте его закрытым и статическим в подклассе. В вашем случае это будет:

 private void rotate(){}
...