Delphi для профессионалов



 

Области видимости


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

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

В модели объектов языка Object Pascal существует механизм доступа к составным частям объекта, определяющий области, где ими можно пользоваться (области видимости). Поля и методы могут относиться к четырем группам (секциям), отличающимся областями видимости. Методы и свойства могут быть общими (секция public), личными (секция private), защищенными (секция protected) и опубликованными (секция published). Есть еще и пятая группа, automated, она ранее использовалась для создания объектов СОМ; теперь она присутствует в языке только для обратной совместимости с программами на Delphi версий 3—5.

Области видимости, определяемые первыми тремя директивами, таковы.

  •  Поля, свойства и методы секции public не имеют ограничений на видимость. Они доступны из других функций и методов объектов как в данном модуле, так и во всех прочих, ссылающихся на него.
  •  Поля, свойства и методы, находящиеся в секции private, доступны только в методах класса и в функциях, содержащихся в том же модуле, что и описываемый класс. Такая директива позволяет полностью скрыть детали внутренней реализации класса. Свойства и методы из секции private можно изменять, и это не будет сказываться на программах, работающих с объектами этого класса. Единственный способ для кого-то другого обратиться к ним — переписать заново созданный вами модуль (если, конечно, доступны исходные тексты).
  •  Поля, свойства и методы секции protected также доступны только внутри модуля с описываемым классом. Но — и это главное — они доступны в классах, являющихся потомками данного класса, в том числе и в других модулях. Такие элементы особенно необходимы для разработчиков новых компонентов — потомков уже существующих. Оставляя свободу модернизации класса, они все же скрывают детали реализации от того, кто только пользуется объектами этого класса.

Рассмотрим пример, иллюстрирующий три варианта областей видимости.

Листинг 1.1. Пример задания областей видимости методов

unit First;             |  unit Second; 

interface               |  interface

                        |   uses First;                                  

type                    |   type

TFirstObj = class       |  TSecondObj =class(TFirstObj}

private                 |  procedure Method4;

procedure Methodl;      |  end;

protected               |

procedure Method2;      |

public                  |

procedure Methods;      |

end;                    |

procedure TestProcl;    |  procedure TestProc2;

implementation          |  implementation

uses dialogs;           |  varAFirstObj :TFirstObj;

var AFirstObj: TFirstObj;|ASecondObj: TSecondObj;

procedure TestProcl;    |  procedure TSecondObj.Method4;

begin                   |  begin

AFirstCbj := TFirstObj.Create; | Methodl; {недопустимо -

AFirstObj.Methodl;(допустимо)|

                          |произойдет ошибка компиляции}

AFirstObj.Method2; {допустимо}| Method2; {допустимо}

AFirstObj.MethodS; {допустимо}| Methods,- {допустимо}

AFirstObj.Free;               | end;

end;

                              | procedure TestProc2;

procedure TFirstObj.Methodl;  | begin

begin                  |AFirstObj:=TFirstObj.Create;

ShowMessage('1');      |AFirstObj.Methodl;{недопустимо}

end;                   |AFirstObj.Method2;{недопустимо}

procedure TFirstObj.Method2;       

                      |AFirstObj.Method3;{допустимо}

begin                 |AFirstObj.Free;

ShowMessage('2');

Methodl;              |ASecondCbj:= TSecondObj.Create;

end;                  |ASecondObj.Methodl;{недопустимо}

procedureTFirstObj.Method3;

|ASecondObj.Method2;{допустимо}

begin                   |ASecondObj.MethodS;{допустимо}

ShowMessage('3');       |ASecondObj.Free;

Method2;                | end;

end;                                        |end.

end.                    | 

Если к этому примеру добавить модуль Third и попробовать вызвать методы классов TFirstObj и TSecondObj оттуда, то к числу недоступных будет отнесен и Method2 — он доступен только в том модуле, в котором описан.

Наконец, область видимости, определяемая четвертой директивой — published, имеет особое значение для интерфейса визуального проектирования Delphi. В этой секции должны быть собраны те свойства объекта, которые будут видны не только во время исполнения приложения, но и из среды разработки. Публиковать можно свойства большинства типов, за исключением старого типа real (теперь он называется rеаl48), свойств типа "массив" и некоторых других. Все свойства компонентов, доступные через

Инспектор объектов, являются их опубликованными свойствами. Во время выполнения такие свойства общедоступны, как и public.

Три области видимости — private, protected, public — как бы упорядочены по возрастанию видимости методов. В классах-потомках можно повысить видимость методов и свойств, но не понизить ее. При описании дочернего класса можно переносить методы и свойства из одной сферы видимости в другую, не переписывая их заново и даже не описывая — достаточно упомянуть о нем в другом месте:

type

TFirstObj = class 

private

FNumber: Integer; 

protected

property Number: Integer read: FNumber;

 end;

...

TSecondObj = class(TFirstObj) 

published

property Number; 

end;

Если какое-либо свойство объекта из состава VCL принадлежит к области public, вернуть его в private невозможно. Напротив, обратная процедура широко практикуется в Delphi. У многих компонентов (например, TEdit) есть предок (в данном случае TCustomEdit), который отличается только отсутствием опубликованных свойств. Так что, если вы хотите создать новый редактирующий компонент, порождайте его на базе TCustomEdit и публикуйте только те свойства, которые считаете нужными. Разумеется, если вы поместили свойство в область private, "достать" его оттуда в потомках возможности уже нет.