интерфейсы и конструкторы в Delphi - PullRequest
10 голосов
/ 03 ноября 2011

Я пишу каркас для бизнес-объектов .. Я интенсивно использую интерфейсы из-за:

1) Автоматическое управление памятью
2) Разделение интересов

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

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

В чем смысл помещения кода создателя в фабричный метод? (что-то, что я до сих пор не использую ..)

Спасибо!

=== РЕДАКТИРОВАТЬ ===

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

Если я не пойду по пути конструктора, я должен пойти по пути «Initialize процедуры» (в интерфейсе) и «CheckObjectInitialized» (защищен) в каждом методе объекта ... как это будет чище?

Ответы [ 4 ]

8 голосов
/ 03 ноября 2011

Метод 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 вызывается только сразу после построения, его легко добавить.

3 голосов
/ 03 ноября 2011

Если вы чувствуете необходимость добавлять конструкторы в свои интерфейсы, вы делаете что-то не так.

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

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

Таким образом, когда вы объявляете интерфейс, контейнер внедрения зависимостей может автоматически создавать / извлекать экземпляр реализованного объекта, избавляя вас от необходимости даже создавать его. Таким образом, ваше приложение становится просто соединением интерфейсов, не заботясь о создании чего-либо. Код вашей библиотеки раскрывается только через контейнер DI.

Delphi Spring Framework предоставляет очень хороший DI-контейнер для использования. Вы можете найти Delphi Spring Framework и Spring Container здесь:

http://code.google.com/p/delphi-spring-framework/

3 голосов
/ 03 ноября 2011

Интерфейсы не устраняют необходимость реализации объектов. Каждый используемый вами интерфейс должен иметь объект реализации. Поэтому ваш код должен вызывать конструкторы.

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

Без использования методов для абстрагирования создания интерфейса вашей цели нет. 2 будет неполным.

1 голос
/ 03 ноября 2011

Презентация Ника Ходжеса на CodeRage просто заявила, что вы должны перенести работу по строительству в класс, который несет единоличную ответственность за создание объектов. Это часто называют «фабричным» шаблоном.

С логической точки зрения это имеет смысл для меня как особого случая «S» в принципах SOLID; Единственная ответственность. Создание объектов должно быть единственной ответственностью (фабрикой), так же как и объединение объектов вместе для решения проблемы (состав одного реального объекта плюс пять смоделированных объектов, будет модульным тестом или составом из пяти реальных объектов для решения реального проблема в производственной кодовой базе).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...