Подтвердить что ты не робот

Функция Delphi: конструктор записи vs factory

Итак, какой будет предпочтительный способ инициализации записей?

С помощью функции factory:

TMyRecord = record
  valueX: integer;
  valueY: integer;
end;

function MyRecord(const AValueX, AValueY: integer): TMyRecord;
begin
  result.valueX := AValueX;
  result.valueY := AValueY;
end;

var
  myrec: TMyRecord;
begin
  myrec := MyRecord(1, 2);
end;

или конструктор:

TMyRecord = record
  valueX: integer;
  valueY: integer;
  constructor Create(const AValueX, AValueY: integer);
end;

constructor TMyRecord.Create(const AValueX, AValueY: integer);
begin
  self.valueX := AValueX;
  self.valueY := AValueY;
end;

var
  myrec: TMyRecord;
begin
  myrec := TMyRecord.Create(1, 2);
end;

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

Почему вы предпочитаете друг друга?

4b9b3361

Ответ 1

Я предпочитаю классы, но если мне приходится использовать записи, мне нравится относиться к ним так же, как и к классам. Поэтому я использую конструктор записи.

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

type 
  TMyRec = record
    ..
    procedure X;
  end;


function GetRec: TMyRec;



procedure Test;
var
  r1, r2 : TMyRec;
begin
  r1 := GetRec;
  r1.X; // internal error
  r2 := r1;
  r2.X; // No internal error;

Ответ 2

Я бы предпочел "factory метод", например

  function TMyRecord.CreateRec(const AValueX, AValueY: integer): TMyRecord;

Отдельные factory функции утечки инкапсуляции и записи конструкторы просто путают IMHO.

Ответ 3

В проекте Delphi, который я создал, я использовал записи вместо классов, чтобы уменьшить количество накладных расходов в списке. У меня было бы несколько сотен записей в динамическом массиве, поэтому я создал две записи. Первая запись была для самого элемента. Поля были сделаны частными (да, вы можете использовать private/protected с записями) и добавили свойства только для чтения в общедоступный раздел. Для инициализации записи был добавлен дополнительный конструктор. Эта настройка позволила мне защитить содержимое этой записи от других разработчиков. Вторая запись была всего лишь оберткой вокруг динамического массива предыдущего типа записи. Массив будет закрытым, и я добавил методы для получения, добавления и удаления записей в этом списке. В результате весь список защищен от неправильного использования другими разработчиками, а также имеет намного меньше накладных расходов, чем регулярное решение TList/TObjectList.

Имейте в виду, что записи не являются классами. Вы не можете наследовать конструкторы и другие методы. У них меньше функциональности, чем истинные классы в средах WIN32. В .NET они снова продвигаются к классам. И не очень полезно использовать добавление конструктора, когда разработчики могут легко изменять содержимое каждого поля в вашей записи. Вместо этого вы должны использовать конструкторы для защиты этих полей.

Ответ 4

Я обычно не создаю конструкторы для записей. Он несовместим со всеми версиями (и FPC). Более того, как правило, они используются только в одном месте, и часто достаточно заполнения.