ООП базируется на трех основных принципах: инкапсуляция, наследование, полиморфизм. Эти принципы ООП работают вместе и практически не существуют отдельно друг от друга.
Инкапсуляция (encapsulation – заключение в капсулу) – это объединение в одном классе данных и действий над ними для сохранения их в безопасности от внешнего влияния. При проектировании объектов программист должен решить, какие части объекта должны быть доступны для пользователя, а какие следует изолировать в объекте. Детали класса, остающиеся невидимыми для пользователя, называются инкапсулированными в классе. Обычно стремятся инкапсулировать как можно большую часть класса.
Наследование – это возможность создания новых объектов, которые обладают свойствами и поведением родительских объектов.
Полиморфизм – это использование единого по названию метода, который по-разному реализован для различных родственных фаз.
Реализация ООП в Delphi (объявление и реализация классов, поля, методы и свойства, создание и уничтожение экземпляров классов, конструкторы и деструкторы).
Реализация ООП в Delphi (объявление и реализация классов, поля, методы и свойства, создание и уничтожение экземпляров объектов, конструкторы и деструкторы).
Инкапсуляция
Для описания объектов служат классы. Каждый объект является экземпляром какого-либо класса.
ООП реализуется в Delphi с использованием типа class, который представляет собой особую структуру, содержащую в своем составе поля, методы и свойства. Ниже приведен пример класса.
Type
TInfo = class
FKey: Integer; // поле
procedure Show; // метод1
function GetKey: Integer; // метод2
constructor Create; // конструктор
destructor Destroy; // деструктор
end;
Методы представляют собой процедуры и функции, принадлежащие объекту. Можно сказать, что методы определяют поведение объекта. Создание метода – процесс из двух этапов. Сначала следует описать метод в объявлении типа, а затем создать код его реализации.
Обычно для реализации одного или нескольких классов используют отдельный модуль. Типы и переменные описывают в части interface, а реализация методов класса происходит в части implementation этого модуля.
Чтобы использовать новый тип в программе, нужно объявить переменную этого типа.
Переменная объектного типа называется экземпляром класса или объектом:
Var
AMyObject: TInfo; // одна переменная
A: array [1..10] of TInfo; // массив переменных
Все экземпляры классов Delphi на самом деле представляют собой 32-х битовые указатели на данные этого экземпляра объекта, расположенные в динамической памяти. При доступе к полям, методам или свойствам объекта компилятор автоматически выполняет скрытые действия, приводящие к возвращению данных по этим ссылкам. В результате для постороннего взгляда объект всегда выглядит как статическая переменная.
Для работы с переменной объектного типа недостаточно только ее описания. Инициализация переменной производится специальным методом, называемым конструктором:
AMyObject:= TInfo.Create;
Конструктор – это функция, возвращающая созданный и проинициализированный объект. В конструкторе обычно присваиваются значения всем полям метода.
constructor TInfo.Create;
Begin
Fkey:= -1;
end;
Конструктор – особый метод. Когда он вызывается, объекта еще не существует и при его вызове используется не имя переменной (как обычно), а имя класса. Конструктор – это метод класса (вызывается с помощью ссылки на класс). Вызов конструктора для создания экземпляра объекта называют созданием экземпляра. При создании экземпляра объекта с помощью конструктора все поля экземпляра будут инициализированы. Все числовые поля будут обнулены, указатели примут значение nil, а строки будут пусты.
Конструктор создает новый объект только в том случае, если перед его именем указано имя класса. Если указать имя уже существующего объекта, он поведет себя по-другому: не создаст новый объект, а только выполнит код, содержащийся в теле конструктора.
Объект уничтожается, когда вызывается метод destructor. Ему дают имя Destroy (никто еще по-другому не называл, хотя можно). Деструктор переопределяют, если при создании объекта выделялась динамическая память. Для нашего простого класса деструктор можно не добавлять, а использовать унаследованный от TObject.
Необходимо взять за правило – всегда уничтожать и освобождать все, что было создано в программе.
Принцип инкапсуляции предполагает отказ от непосредственного обращения к полям класса. Для доступа к полям обычно используются свойства.
Свойства объекта (property) – это специальные средства доступа к полям объекта, позволяющие изменять данные его полей и выполнять код его методов. Обычно свойство определяется тремя элементами: полем и двумя методами, которые осуществляют его чтение/запись:
Type
TMyClass = class
FKey: Integer;
...
function GetKey: Integer;
procedure SetKey(const Value: Integer);
property Key: Integer read GetKey write SetKey;
...
end;
Соответствующие реализации:
function TMyClass.GetKey: Integer;
Begin
Result:= FKey;
end;
procedure TMyClass.SetKey(const Value: Integer);
Begin
if Fkey <> ANewKey then
Begin
Fkey:= ANewKey;
... // здесь могут выполняться дополнительные действия
end;
end;
В методах, входящих в состав свойств может осуществляться проверка устанавливаемой величины на попадание в допустимый диапазон значений и вызов других процедур, зависящих от вносимых изменений. Если же потребности в специальных процедурах чтения и/или записи нет, можно вместо имен методов применять имена полей:
Type
TMyClass = class
FKey: Integer;
...
procedure SetKey(const Value: Integer);
property Key: Integer read FKey write SetKey;
...
end;
Если свойство должно только читаться или только записываться, в его описании может присутствовать только соответствующий метод:
Type
TMyClass = class
FKey: Integer;
...
property Key: Integer read FKey;
...
end;
Попытка присвоить значение свойству вызовет ошибку компиляции.