Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
методички по информатике / Конспект лекций (Delphi).pdf
Скачиваний:
63
Добавлен:
27.05.2015
Размер:
1.2 Mб
Скачать

37

2. ОСНОВНЫЕ ПОЛОЖЕНИЯ ООП

Развитие ООП обусловлено рядом причин. Одна из них – увеличение сложности программного обеспечения, вызванное:

сложностью предметной области – затрагивание все более широких областей реальности приводит к тому, что понять целиком систему становится все труднее. Кроме того, пользователю все труднее объяснить разработчику в доступной форме, что он хочет. Дополнительную сложность вызывает внесение корректировок в разрабатываемый проект. Применение ОО подхода снижает данную сложность;

трудностью управления процессом разработки – современные программные продукты могут содержать миллионы строк кода на языке высокого уровня, разобраться в которых одному человеку невозможно. Поэтому разработкой занимается группа разработчиков, между которыми необходимо четкое взаимодействие для поддержания единства и целостности разработки. Разбиение проекта на отдельные модули, формирование иерархии классов объектов способствует этому;

необходимостью обеспечивать достаточную гибкость программы – в программной индустрии почти нет стандартов, поэтому разработчик, как правило, создает сотни мелких базовых блоков, из которых строится программа более высокого уровня. При этом в эти блоки, зачастую, закладывается больший, чем требуется в настоящий момент, объем возможностей для обеспечения гибкого видоизменения системы в дальнейшем;

неудовлетворительным способом описания поведения больших дискретных систем – в каждый момент времени система находится в определенном дискретном состоянии, характеризуемом текущими значениями переменных, их адресов, адресов стека и т.д. Однако возможен переход из одного дискретного состояния в другое, не учтенное разработчиком, в котором возможен крах системы. Разбиение сложной системы на части, их отдельное описание и тестирование, организация как можно меньшего числа каналов взаимодействия между составными частями позволяет уменьшить вероятность краха системы.

На преодоление этих сложностей и было направлено постепенное изме-

нение языков программирования, основные поколения которых характеризуются:

1 поколение, начало 2: FORTRAN, COBOL – имеют простую структуру, состоящую из глобальных данных и подпрограмм. Так как область данных доступна всем подпрограммам, то ошибка в одной из них может иметь далеко идущие последствия. Наличие большого числа перекрестных связей между подпрограммами постепенно приводит к трудности в схемах управления и при поиске ошибок;

конец 2 и начало 3 поколения – появление средств передачи параметров между подпрограммами, вложенности подпрограмм, определение областей видимости, возможность использовать подпрограммы как готовые блоки;

38

конец 3 поколения: FORTRAN II –появление модулей. Однако нет четких интерфейсов модулей и имеется возможность вызова подпрограммы с несоответствующими параметрами. Сохраняется возможность совместного использования общей области данных модулей;

ООЯ: основа – модуль, составленный из логически связанных классов и объ-

ектов. “Объект – сущность, объединяющая процедуры и данные, производящая вычисления и сохраняющая свое локальное состояние”. При объектном подходе акцент переносится на конкретные характеристики физической или абстрактной системы. Объекты может только менять состояние, вести себя, управляться или становиться в определенное отношение к другим объектом. Свойства, характеризующие объект и его поведение остаются неизменными, и это должны учитывать другие объекты. Поэтому взаимодействие, в основном, осуществляется через методы объектов, и уменьшена или отсутствует

область глобальных данных.

Объектно-ориентированное программирование – это методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования.

Описание класса объектов в среде Delphi осуществляется следующим образом:

<имя класса> = class[<имя класса-родителя>] constructor Create;

destructor Destroy; override; private

aValue : integer;

aData : array[1..10] of double; procedure SetValue(NewValue : integer); procedure SetData(Index : integer);

function GetData(Index : integer) : double;

protected

public

property Value : integer read aValue write SetValue default 0; property Data[Index : integer] : double read GetData write Set-

Data; default;

published

end;

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

Абстракция выделяет существенные характеристики некоторого объекта, отличающие его от всех других видов объектов и, таким образом, четко определяя его концептуальные границы с точки зрения наблюдателя.

39

Пример – кошка со стороны домашней хозяйки и ветеринара.

Пример: теплица с датчиками температуры, влажности, освещения и т.д. Датчик характеризуется месторасположением, а также контролируемым значением, которое он по запросу должен возвращать.

TCustomSensor = class

constructor Create(InitX, InitY, InitZ : word); private

public

property X : word read aX; property Y : word read aY; property Z : word read aZ;

property Value : double read aValue; end;

Будем называть объект, использующий ресурсы другого объекта, клиентом, а объект предоставляющий ресурсы – сервером. В этом случае сервер несет на себе ряд обязательств перед клиентом (в нашем примере: возможность дать информацию о месте расположения датчика и значении контролируемого параметра). Однако и клиент обязан требовать от сервера только то, что сервер может предоставить. Такие взаимоотношения объектов называются контрактной моделью. При нарушении контракта одной из сторон возникает исключительная ситуация, которая может быть обработана специальным образом как самими участниками контракта, так и третьим объектом.

Инкапсуляция – это процесс отделения друг от друга элементов объекта, определяющих его устройство и поведение; инкапсуляция служит для того, чтобы изолировать контрактные обязательства абстракции от их реализации.

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

Пример: введение нагревателей. Пусть в теплице помимо различных датчиков имеются устройства поддержания климата, одно из которых – нагреватели, расположенные в различных местах и подключенные к различным портам управляющей машины.

THeater = class

private

protected

Port : integer;

procedure OnOff(NewIsOn : boolean); public

property X : word read aX; property Y : word read aY; property Z : word read aZ;

40

property IsOn : boolean read aIsOn write OnOff; end;

Используемый для включения и выключения метод OnOff посылает в порт машины с индексом Port соответствующий сигнал, например

procedure THeater.OnOff(NewIsOn : boolean); begin

if NewIsOn and (not aIsOn) then begin

SetPort(Port, True); aIsOn := True;

end else

if (not NewIsOn) and aIsOn then begin

SetPort(Port, False); aIsOn := False;

end;

end;

Предположим, что произошла смена нагревателей, и теперь вместо посылки сигнала в последовательные порты необходимо заносить команду в ка- кую-либо ячейку памяти. В этом случае для разработчика, использующего объект THeater ничего не меняется, так как поменяется только скрытая от него часть объекта (например, метод OnOff).

Модульность – это свойство системы, которая была разложена на внутренне связанные, но слабо связанные между собой модули.

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

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

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

Иерархия – это упорядочивание абстракций, расположение их по уров-

ням.

41

В Delphi основным видом иерархии является концепция наследования, которая заключается в том, что “потомок” заимствует структурную и функциональную часть “родителя”. При этом “потомок” может достраивать или переписывать компоненты “родителя”.

Пример: активный датчик.

type

TCustomActiveSensor = class(TCustomSensor) private

procedure Activate; virtual; procedure Control;

public

property ControlValue : double read aControlValue write SetControlValue;

property Delta : double read aDelta write SetDelta; end;

procedure TCustomActiveSensor.Control; begin

if abs(Value-ControlValue)>Delta then Activate;

end;

type

TTemperatureSensor = class(TCustomActiveSensor) private

procedure Activate; override; public

end;

TLigthSensor = class(TCustomActiveSensor) private

procedure Activate; override; public

end;

var

ActiveSensor : TCustomActiveSensor; TemperatureSensor : TTemperatureSensor; LigthSensor : TLigthSensor;

begin

ActiveSensor := TemperatureSensor; ActiveSensor.Activate; ActiveSensor := LigthSensor; ActiveSensor.Activate;

TemperatureSensor := ActiveSensor; (недопустимо присваивание ро-

42

дителя потомку)

TemperatureSensor := LigthSensor; (не находятся в состоянии под-

чиненности)

end.

Виртуальные методы “родителя” и “потомка” должны иметь одинаковый набор параметров, при этом у “потомка” вместо директивы “virtual” необходимо использовать “override”. Если будет применено директивы “virtual”, то произойдет скрытие метода “родителя” и будет дано предупреждение об этом. В случае разумного скрытия метода “родителя” данное предупреждение можно подавить директивой “reintroduce”.

(Привести графическую интерпретацию таблицы виртуальных методов).

Здесь полиморфизм – одно и то же имя может означать объекты разных классов, но имея общего предка, все они имеют общее подмножество операций, которые можно над ними выполнять.

Таким образом наиболее общие абстракции создают систему базовых классов, от которой происходит развитие всей системы.

Операторы работы с классами:

as – оператор приведения, позволяющий присвоить объект одного класса переменной другого класса. В приведенном выше примере, например, возможно присвоение следующего вида

TemperatureSensor := ActiveSensor as TTemperatureSensor.

Применение as расширяет диапазон возможностей программиста, однако в этом случае ответственность за правильность работы возлагается на него. Примером использования данного оператора является работа с элементами коллекций.

is – оператор проверки класса. Результатом выполнения данного оператора будет логическое значение, например, результатом выполнения

TemperatureSensor is TTemperatureSensor будет True.

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

Перегруженные методы.

Перегрузка методов позволяет использовать одно и то же имя метода для описания более одного метода. При этом, методы должны отличаться набором параметров, а после каждого из методов используется ключевое слово “overload”. Например, можно реализовать функцию деления отдельно для целых и вещественных чисел:

type

TCustomClass = class public

function Divide(x, y : integer) : integer; overload; function Divide(x, y : double) : double; overload;

end;

43

function TCustomClass.Divide(x, y : integer): integer; begin

Result := x div y; end;

function TCustomClass.Divide(x, y : double): double; begin

Result := x/y; end;

Как и в случае с виртуальными методами, при возникновении предупреждения о скрытии родительского метода, его можно подавить директивой

reintroduce”.