Полиморфизм
Рассмотрим внимательно следующий пример. Пусть у нас имеются некое обобщенное поле для хранения данных — класс
TFieid и три его потомка — для хранения строк, целых и вещественных чисел:
type
TField = class
function GetData:string; virtual; abstract;
end;
TStringFieid = class(TField)
FData : string;
function GetData: string; override;
end;
TIntegerField = class(TField)
FData : Integer;
function GetData: string;override;
end;
TExtendedField = class(TField)
FData : Extended;
function GetData: string;override;
end;
function TStringFieid.GetData;
begin
Result := FData
end;
function TIntegerField.GetData;
begin
Result := IntToStr(FData);
end;
function TExtendedField.GetData;
begin
Result:= FloatToStrF(FData, ffFixed, 7, 2);
end ;
procedure ShowData(AField : TField);
begin
Forml.Label!.Caption := AField.GetData;
end;
В этом примере классы содержат разнотипные поля данных
FData и только-то и "умеют", что сообщить о значении этих данных текстовой строкой (при помощи метода
GetData). Внешняя по отношению к ним процедура
ShowData получает объект в виде параметра и показывает эту строку.
Правила контроля соответствия типов (typecasting) языка Object Pascal гласят, что объекту как указателю на экземпляр объектного типа может быть
присвоен адрес любого экземпляра любого из дочерних типов.
В процедуре showData параметр описан как
TFieid — это значит, что в нее можно передавать объекты классов
и TStringField,и TIntegerField,
и TExtendedField,и любого другого потомка класса
TFieid.
Но какой (точнее, чей) метод GetData при этом будет вызван? Тот, который соответствует классу фактически
переданного объекта. Этот принцип называется полиморфизмом,
и он, пожалуй, представляет собой наиболее важный козырь ООП.
Допустим, вы имеете дело с некоторой совокупностью явлений или процессов. Чтобы смоделировать их средствами ООП, нужно выделить их самые общие, типовые черты. Те из них, которые не изменяют своего содержания, должны быть реализованы в виде статических методов. Те же, которые изменяются при переходе от общего к частному, лучше облечь в форму виртуальных методов.
Основные, "родовые" черты (методы) нужно описать в классе-предке и затем перекрывать их в классах-потомках. В нашем примере программисту, пишущему процедуру вроде
showData, важно лишь, что любой объект, переданный в нее, является потомком
TFieid и он умеет сообщить о значении своих данных (выполнив метод
GetData). Если, к примеру, такую процедуру скомпилировать и поместить в динамическую библиотеку, то эту библиотеку можно будет раз и навсегда использовать без изменений, хотя будут появляться и новые, неизвестные в момент ее создания классы-потомки
TFieid.
Наглядный пример использования полиморфизма дает среда Delphi. В ней имеется класс
TComponent, на уровне которого сосредоточены определенные "правила" взаимодействия компонентов со средой разработки и с другими компонентами. Следуя этим правилам, можно порождать от класса
TComponent свои компоненты, настраивая Delphi на решение
специальных задач.
Теперь, надеемся, стало более или менее ясно, какие преимущества ООП позволили ему стать основным способом разработки серьезного программного обеспечения. Те, кто начинал программировать еще для Windows 3.0, наверняка помнят, сколько усилий требовалось при написании совершенно тривиального кода. Сейчас для того же самого в Delphi достаточно буквально пары щелчков мышью. На самом деле именно сложность программирования для Windows стала катализатором внедрения ООП.
|