Всё внутри
В Delphi методы должны объявляться внутри класса, а описываться — вне класса, при этом перед именем метода пишется имя класса с последующей точкой:
type
Person = class
private
nm: string; // имя
ag: integer; // возраст
procedure SetAge(ag: integer);
public
constructor Create(nm: string; ag: integer);
property Name: string read nm;
property Age: integer read ag write SetAge;
end;
constructor Person.Create(nm: string; ag: integer);
begin
Self.nm := nm;
Self.ag := ag;
end;
procedure Person.SetAge(ag: integer);
begin
if ag<0 then
ag := 0;
Self.ag := ag;
end;
Удобен ли такой метод? Несомненно: при взгляде на класс сразу виден его интерфейс. А реализация дана ниже. Если класс находится в модуле, то его интерфейс помещается в интерфейсную секцию модуля, а реализация методов — в секцию реализации модуля.
Немного раздражают лишние детали: например, для использования класса достаточно знать его открытый интерфейс и вовсе не нужно знать, какие методы используются для чтения и записи свойств. То есть в идеале для пользователя класс должен предстать в следующем обличье:
type
Person = class
public
constructor Create(nm: string; ag: integer);
property Name: string read;
property Age: integer read write;
end;
В Java и C# принято прямо противоположное решение: все методы определяются только внутри интерфейса класса. Например, тот же класс на C# будет описываться так.
При таком способе все описывается сразу, что очень удобно, но есть две проблемы. Во-первых, интерфейс класса становится труднообозримым. Во-вторых, трудно перемещаться по большому классу в 200–300–1000 строк в поисках нужного метода. Обе проблемы решаются специальными средствами оболочки, позволяющими вычленять из класса его интерфейс и перемещаться к нужному методу.
В C++ принято демократичное решение: методы могут описываться как внутри, так и вне класса. Это очень удобно: мелкие методы реализуются на месте, более крупные выносятся вовне, чтобы не захламлять интерфейс класса.
В PascalABC.NET принято такое же демократическое решение: методы можно определять как внутри, так и вне интерфейса класса. Например, код нашего класса можно записать следующим образом:
type
Person = class
private
nm: string; // имя
ag: integer; // возраст
procedure SetAge(ag: integer);
begin
if ag<0 then
ag := 0;
Self.ag := ag;
end;
public
constructor Create(nm: string; ag: integer);
begin
Self.nm := nm;
Self.ag := ag;
end;
property Name: string read nm;
property Age: integer read ag write SetAge;
end;
Конечно, наследуются недостатки обоих способов. Но есть и преимущества. Они просты.
1. Класс как оболочка над данными и подпрограммами
При начальном обучении классам достаточно сказать, что класс — это всего лишь оболочка над переменными и подпрограммами, объединяющая их в единое целое. Пренебрежем пока защитой данных и явным конструктором:
type
Person = class // оболочка
Name: string;
Age: integer;
procedure Print;
begin
Println(Name,Age);
end;
end;
Это целое является типом, которым можно пользоваться как обычным типом: описывать переменные этого типа (объекты) и пользоваться ими, используя точечную нотацию для вызова этих подпрограмм (методов) и обращения к этим переменным (полям). Только сконструировать эту переменную надо перед первым использованием:
var p: Person := new Person; // сконструировать новый объект — обязательно
p.Name := 'Иванов';
p.Age := 18;
p.Print;
Все просто. Такой способ изложения позволяет рассказывать о классах практически сразу после темы «Подпрограммы».
Еще можно добавить, что внутри класса можно написать свой метод-конструктор с параметрами:
constructor (nm: string; ag: integer);
begin
Name := nm;
Age := ag;
end;
Да-да, в PascalABC.NET имя можно не добавлять. Но если уж добавили — помните: все конструкторы в PascalABC.NET должны именоваться Create.
Тогда предыдущий код упростится:
var p: Person := new Person('Иванов',18);
p.Print;
2. Методы удобно описывать сразу
При написании кода программы на доске (да-да, еще кое-где все еще пишут на доске!) гораздо проще описывать методы класса сразу.
И еще одно маленькое замечание. Если уж так страшно использовать конструкторы классов, можно воспользоваться записями — в PascalABC.NET в записях тоже могут быть методы, и они могут описываться внутри.
Повторим предыдущий код для записей для лучшей обозримости:
type
Person = record
Name: string;
Age: integer;
procedure Print;
begin
Println(Name,Age);
end;
end;
begin
var p: Person;
p.Name := 'Иванов';
p.Age := 18;
p.Print;
end.