Java: запретить определенные методы из расширенного класса? - PullRequest
1 голос
/ 29 марта 2012

Я создал класс Vector2D, который расширяет Point2D.Double.

A Vector2D имеет два поля: величину и направление. Расширение Point2D.Double позволяет вектору также сохранять начальную позицию.

Мне нравится возможность сделать это:

Vector2D myVector = new Vector2D(50, 50);  // instantiated without direction or magnitude
Point2D.Double myPoint = new Point2D.Double(myVector.getLocation());

Однако я бы хотел запретить это:

Point2D.Double myPoint = myVector;

А это:

Point2D.Double myPoint.setLocation(myVector);

Поскольку обе эти операции обрабатывают myVector, как если бы оно было , просто a Point2D.Double.

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

Есть ли способ запретить Vector2D методы или операторы, которые существуют в Point2D.Double?

Ответы [ 3 ]

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

Я не вижу проблемы здесь. Если вы хотите, чтобы Vector2D был подклассом Point2D.Double, то вы явно заявляете, что это IS a Point2D.Double. Если клиент хочет использовать его как Point2D.Double, это разрешено и абсолютно законно.

Звучит так, как будто вы пытаетесь создать подклассы как систему повторного использования кода, а не как настоящие отношения. Обычно это считается анти-паттерном.

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

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

Это невозможно на уровне типа из-за того, как работает система подтипов Java и принцип замены Лискова . (Существуют и другие языки, такие как Eiffel , которые do допускают этот шаблон!)

Понятие Лискова о [поведенческом] подтипе определяет ... если S является подтипом T, то объекты типа T в программе могут быть заменены объектами типа S без изменения [этой программы] ....

Если используется наследование , лучшее , которое можно сделать, это выбросить «Не поддерживается исключение» или, как указано, ничего не делать. (Обратите внимание, что это фактически нарушает LSP, который включает поведенческую корректность как требование!)

Если бы использовалось несколько дискретных интерфейсов - но их здесь нет - тогда можно было бы выбрать и выбрать, какие интерфейсы реализовать (что можно сделать с помощью композиции). Однако с композицией (или другим несвязанным типом) один не может использовать пользовательский Vector2D в качестве Point2D.Double , и, таким образом, Java показывает, как легко связываться с подтипы ;-) В настоящее время я склоняюсь к нескольким специализированным интерфейсам.

Если допустимы явные преобразования , то Vector2D.fromPoint2D(...) и Vector2D.toPoint2D(...) - это один подход, который может быть допустимым ...

Удачного кодирования.

1 голос
/ 29 марта 2012

Нет, это нельзя запретить.

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

Vector2D myVector = new Vector2D(50, 50);  // instantiated without direction or magnitude
Point2D.Double myPoint = new Point2D.Double(myVector.getLocation());

Не уверен, что есть чистый способ справиться с этим. Интересно, какой у вас сценарий использования, вам нужно такое поведение?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...