Философия Java


Взаимозаменяемые объекты с полиморфизмом


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

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

Однако, существует проблема, когда пробуют трактовать унаследованный тип как объект базового типа (окружность - как форма, велосипед - как транспортное средство, баклана - как птицу и т.п.). Если функция предназначена для сообщения родительской форме о необходимости нарисовать себя или родительскому транспортному средству - управлять, или родительской птице - лететь, компилятор не может знать точно во время компиляции, какой кусок кода будет исполнен. Это то место когда сообщение послано, а программист не хочет знать, какой кусок кода будет исполнен. Функция рисования может быть одинаково применена к окружности, к квадрату или к треугольнику, и объект должен выполнять правильный код в зависимости определенного для него типа. Если вы не знаете какая часть кода будет выполнена, то когда вы добавляете новый подтип, то выполняемый код может отличаться, и это не потребует изменений при вызове функции. Поэтому, компилятор не может знать точно какая часть кода выполнилась, но что делает это? Например, в приведенной диаграмме КонтроллерПтицы объект работает только с родительским объектом Птица и не знает какой точно тип имеется. Это удобно с точки зрения КонроллераПтицы, так как нет необходимости писать специальный код для определения точного типа Птицы, с которой идет работа, или поведения Птицы. Если это так, то когда вызывается move( ) при игнорировании определенного типа Птицы, как воспроизведется правильное поведение (бег, полет или плаванье Гуся и бег или плаванье Пингвина)?




Начало  Назад  Вперед



Книжный магазин