Использование наследования для изменения интерфейса суперкласса

#java #design-patterns #inheritance #interface

#java #шаблоны проектирования #наследование #интерфейс

Вопрос:

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

Я использую существующий физический движок (Phys2D) для разработки своего рода игры. Этот физический движок имеет Body объекты, управляемые World , и к ним применяются различные силы по мере изменения ступенчатого мира. Для искусственного интеллекта в игре важно, чтобы тела имели цвета (чтобы их можно было распознать), но это не поддерживается физическим движком, поэтому я создал подкласс и расширил Body класс, включив в него это — http://pastebin.com/1nLYWg3w . Теперь, когда я создаю эти Body экземпляры, я могу получить их обратно из World и получить их цвета.

Однако Netbeans утверждает, что это

 cannot find symbol
    symbol:   method getColour()
    location: class net.phys2d.raw.Body
  

потому что Body объекты, возвращаемые интерфейсом физического движка, не содержат этого метода. Я знаю, что во время выполнения все Body объекты, которые передаются в World , на самом деле будут объектами ColouredBody типа, и поэтому этот метод будет определен в их интерфейсах.

Как я могу прикрепить цвета к Body объектам и не создавать пугающих подчеркиваний и предупреждений? Я понимаю, что могу изменить сам Phys2D, но, если отбросить потенциальные лицензионные ограничения (в лицензии указано, что вы можете сделать это с помощью Phys2D), мне сказали, что это плохая практика.

Комментарии:

1. Я связался с pastebin, чтобы не загромождать вопрос. Пожалуйста, сообщите, будет ли это более уместно в самом сообщении. Кроме того, если есть какой-либо способ, которым я могу сделать сообщение более общим для других людей, пожалуйста, отредактируйте или запросите необходимые изменения.

Ответ №1:

Если во время выполнения вы знаете, что все ваши Body объекты на самом деле ColouredBody , то вы можете привести эти объекты к ColouredBody и вызвать getColour :

 Body body = ...;
ColouredBody colouredBody = (ColouredBody) body;
colouredBody.getColour();
  

Ответ №2:

На самом деле, я бы сказал, что было бы совершенно неплохо добавить свойство colour к классу Body самого движка.

Если вы не можете или не хотите этого делать, все, что вам нужно сделать, это привести Body экземпляры к ColouredBody перед их использованием:

 ((ColouredBody)body).getColour();
  

Это сообщает компилятору «Я знаю, что body это действительно экземпляр ColouredBody , поэтому позвольте мне использовать его как один», но если в любой момент окажется, что это не так, вы получите ClassCastException .

Комментарии:

1. Большое спасибо. Я собираюсь отредактировать существующий класс, поскольку это кажется намного более элегантным. Если бы мне не разрешалось редактировать библиотеку, и если бы не было более простых вариантов, я бы использовал cast.

Ответ №3:

Вы можете привести к конкретному типу:

 ColouredBody cbody = (ColouredBody) body;
  

желательно, просто чтобы избежать проблем, вы можете проверить, действительно ли это так:

 if (body instanceof ColouredBody) {..}
  

Обратите внимание, что понижение (от более общего к более конкретному классу) обычно считается плохой практикой.

Если это возможно, вы можете попытаться расширить World с ColouredWorld помощью Body и переопределить методы, которые возвращают ColouredBody значение return, на return, которые возвращают, и также хранить тела в соответствующей коллекции, но это может быть излишним в зависимости от сложности.