Метод Factory позволит вам регистрировать разработчиков ваших интерфейсов в одном месте, а остальной код будет «просто запрашивать разработчика».
Factory.GetImplementorOf(IMyInterface)
, который затем возвращает ссылку на интерфейс.
Это зависит от вас, как вы хотите реализовать фабрику. Вы можете создавать новые экземпляры для каждого запрошенного интерфейса, поддерживать пул уже созданных экземпляров и возвращать ссылки на них или выполнять смешивание в зависимости от запрошенного интерфейса.
Вы также можете решить, хотите ли вы, чтобы ваша фабрика позволяла нескольким разработчикам одного и того же интерфейса (как вы выбираете правильный тогда) или применяете один разработчик для каждого интерфейса или комбинацию.
Несколько экземпляров могут пригодиться, например, при работе с дублирующимися (d) сервисами, которые иногда могут быть недоступны, поэтому вы можете выбрать тот, который работает.
Также может быть идея предоставить GetImplementorOf (массив интерфейсов). Таким образом, вы можете иметь несколько разработчиков IDump, но различать их по способу, которым они выводят информацию: например, разработчик, который IDump является объектом в формате IHTML.
- фабрики, подготовленные для работы с параметрами конструкторов в некоторых
чистый путь ??
Ну, это интересный вопрос. Нет, сами по себе они не являются. Фабрики обычно работают со стандартным конструктором, возможно, с параметром «Владелец» и / или «Id».
Если вам нужно больше конкретных конструкторов для каждого класса, вы должны
- создает больше фабрик, что лишает возможности иметь единую точку для регистрации разработчиков интерфейсов
- допускает методы инициализации для каждого интерфейса / класса, которые должны вызываться сразу после построения, что открывает ваш код для забвения и делает классы менее неизменными.
- или придумали способ включить знание фабричной подписи в фабрику.
На одном этапе я выбрал третий вариант. Создавая фабрику, которая
- требуется регистрация интерфейса с абстрактным базовым классом
- требуется, чтобы разработчики вышли из абстрактного базового класса
- возвращает экземпляры как ссылку на метакласс вместо экземпляра
TFactory = class(...)
public
procedure RegisterInterface(const aGUID: TGUID; const aAbstractBase: TClass);
procedure RegisterImplementor(const aGUID: TGUID; const aImplementor: TClass);
function GetImplementor(const aGUID: TGUID): TClass;
Недостатки:
- Довольно сложно объявить как интерфейс, так и абстрактный базовый класс.
- Это устраняет преимущество «множественного наследования по интерфейсу» интерфейсов на одном языке наследования.
- Вам нужно распространить знания о паре интерфейс / базовый класс по всему вашему коду, иначе вы все равно не сможете использовать конструкторы, специфичные для класса. Здесь могут помочь дженерики, но я еще не рассматривал это.
- Это не имеет смысла, если у вас нет нескольких разработчиков одного и того же (набора) интерфейсов.
- Даже если вам нужно несколько разработчиков только для модульного тестирования, это кажется излишним. Я нашел фиктивные классы, объявленные в тестовом модуле с соответствующими частями интерфейса класса, более полезными и эффективными.
В общем, я вернулся к стандартному методу конструктор / особая пара инициализации. Должно быть довольно легко написать модульный тест сканирования кода, чтобы проверить, что после каждого вызова GetImplementor с завода следует вызов Initialization. И хотя класс в теории больше не является таким же неизменным, как это было бы с определенным конструктором, он все еще предназначен для всех практических целей. И если вы хотите убедиться, что метод Initialize вызывается только сразу после построения, его легко добавить.