Автоматическое создание объектных полей с помощью RTTI в Delphi

Вольный перевод поста Automagically Creating Object Fields with RTTI

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

Проблема

Мне нужны классы следующего вида

Но я слишком ленив чтобы писать в каждом классе раз примерно одинаковый конструктор и деструктор. Что мне делать?

Читать далее Автоматическое создание объектных полей с помощью RTTI в Delphi

Конструкторы записей (record) в Delphi

Вольный перевод поста Record Constructors in Delphi

Конструкторы записей в Delphi — особенность языка которая вызывает вопросы. Зачем они нужны и когда их использовать вместо методов записей? В документации Delphi написано следующее:

Records are constructed automatically, using a default no-argument constructor, but classes must be explicitly constructed. Because records have a default no-argument constructor, any user-defined record constructor must have one or more parameters.

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

Приведённая выше документация ничего не объясняет. В Delphi не существует такой вещи как "конструктор по умолчанию без параметров". Сразу возникает ещё один вопрос — почему в Delphi запрещены конструкторы без параметров и разрешены с параметрами?

На самом деле конструкторы записей в Delphi это просто специальный синтаксис для методов записей.

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

или процедуру

Используя конструктор в записи вы можете совместить обе формы

Можно вызывать конструктор как функцию

или как процедуру

Обе формы корректны.

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

Условная компиляция и возможности языка Delphi

Вольный перевод поста Conditional Compilation with Features.

Вы разрабатываете код который должен работать в разных версиях Delphi? Вы устали от написания примерно такого кода?

При этом вы

  • никогда не знаете точно когда определённая возможность была введена в Delphi
  • всегда сомневаетесь в том какая версия Delphi имеет версию компилятора (CompilerVersion) равную 22

Вместо написания условий по версии компилятора, вы можете думать в терминах возможностей языка. Код выше требует версию Delphi которая поддерживает обобщённое программирования и содержит реализацию TArray<T>. Так что можно переписать код примерно так

Это проще для написания (так как не нужно помнить что в какой версии добавлено) и проще для понимания.

Директивы для таких проверок можно подключить из файла jedi.inc. В этом файле содержатся директивы вида HAS_XXXXX и SUPPORTS_XXXXX, например, такие как

Предварительное объявление записей (record) в Delphi

Вольный перевод поста Forward record declaration.

Предварительная объявление не новая концепция. Она уже присутствовала в оригинальном Паскале Вирта, где она позволяла программистам делать только одну вещь — вызывать процедуру A из процедуры B и вызывать процедуру B из процедуры A. В те времена не было интерфейсов, классов, модулей, только процедуры и функции. Вот пример

Более знакомая современная концепция — предварительное объявление для классов и интерфейсов.

В тоже время в Object Pascal нет концепции предварительного объявления записей. Следующий код не компилируется

Существует трюк который позволяет достичь аналогичной функциональности с помощью другого синтаксического сахара - record helpers. Мы можем удалить объявление TRecB.Other из TRecB и потом снова добавить его через хелпер для TRecB.

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

Фундаментальные принципы объектно ориентированного проектирования (Часть 1): Абстракция

Вольный перевод статьи Fundamental Object Oriented Design principles (Part 1): Abstraction

Рассмотрим принцип Абстракции используемый в объектно ориентированных языках программирования.

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

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

Эта статья предполагает что вы знакомы как минимум с одним ОО языком программирования. C++, Delphi, C# и Java являются примерами объектно ориентированных языков. Настоящий ОО язык программирования имеет классы, объекты и очень часто интерфейсы.

Что такое Абстракция?

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

Читать далее Фундаментальные принципы объектно ориентированного проектирования (Часть 1): Абстракция

Области видимости элементов классов Delphi

Для контроля доступа к полям, методам и свойствам классов используются области видимости. В Delphi есть следующие области видимости:

  • public
  • published
  • strict private
  • private
  • strict protected
  • protected

Рассмотрим их на примерах.

Читать далее Области видимости элементов классов Delphi

Правильная обработка освобождения ресурсов через try…finally в Delphi

Есть много разных вариантов как можно использовать конструкцию try...finally для освобождения ресурсов. Многие из них работают неверно в особых ситуациях. Рассмотрим несколько вариантов подробнее.

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

Прежде всего, установим ReportMemoryLeaksOnShutdown := True в dpr файле, для того чтобы отслеживать утечки памяти.

Читать далее Правильная обработка освобождения ресурсов через try…finally в Delphi

Автоматическая инициализация переменных в Delphi

Переменные в Delphi можно разделить на три типа

  • Глобальные
  • Локальные
  • Поля объектов

Разные типы имеют свои особенности инициализация по умолчанию. Глобальные переменные — переменные которые объявлены в теле модуля всегда инициализируются автоматически. Например, числовые типы всегда будут равны нулю.

Читать далее Автоматическая инициализация переменных в Delphi

Преобразование типов значений Null и Unassigned типа Variant в Delphi

Конвертация Unassigned

Если переменная с типом Variant не инициализирована то она имеет значение Unassigned, даже если это поле класса:

Возможны следующие случаи преобразования Unassigned в другие типы данных:

Читать далее Преобразование типов значений Null и Unassigned типа Variant в Delphi

Примеры порождающих паттернов из Банды четырёх (GoF) на Delphi

Вольный перевод статьи Gang-of-Four Creational Design Pattern Examples in Delphi

Специализированная для Delphi версия Порождающих паттернов из книги “Design Patterns: Elements of Reusable Object-Oriented Software”.

Абстрактная фабрика (Abstract Factory)

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

В этом примере используются интерфейсы вместо абстрактных классов, которые используются в примерах в книге. Любое количество конкретных классов могут реализовывать интерфейс фабрики.

Читать далее Примеры порождающих паттернов из Банды четырёх (GoF) на Delphi