Всё внутри

Просмотров: 7842

В 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
      writeln(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
      writeln(Name,' ',Age);
    end;
end;
 
var p: Person;
 
begin
  p.Name := 'Иванов';
  p.Age := 18;
  p.Print;
end.

Новости

19.01.17. Добавлена операция безопасного среза: a?[-1:5:2]

29.08.16. Вышла версия 3.2. Реализован оператор yield.

12.02.16. Вышла версия 3.1. Добавлены кортежи в стиле (a,b) и кортежное присваивание (a,b) := (b,a)

31.12.15. Версия 3.0.0.1128. Реализованы обобщенные методы расширения для операций

Случайная программа

// Алгоритм Евклида нахождения НОД
// Уровень сложности: 0

function GCD(a,b: integer): integer;
begin
  while b<>0 do
  begin
    var c := a mod b;
    a := b;
    b := c;
  end;
  Result := a;
end;

begin
  var a,b: integer;
  writeln('Введите a,b: ');
  read(a,b);
  
  writeln('НОД = ',GCD(a,b));
end.