2015-07-31 1 views
4

Я столкнулся с проблемой правильного создания экземпляра объекта из типа, разрешенного контейнером Framework Spring4D.Delphi: вызывать родительский конструктор с использованием интерфейса (Spring4D framework)

У меня есть класс:

type 
    TSurvey = class (TInterfacedObject, ISurvey) 

    private 
     _id : Integer; 
     _organization : IOrganization; 

     function GetId() : Integer; 
     procedure SetId (const value : Integer); 

     function GetOrganization() : IOrganization; 
     procedure SetOrganization (const value : IOrganization); 

    public 
     property Id : Integer read GetId write SetId; 
     property Organization: IOrganization read GetOrganization write SetOrganization; 
end; 

... 

initialization 

    GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>.InjectField ('_organization'); 

... 

Я использую GlobalContainer для создания экземпляра объекта:

survey := GlobalContainer.Resolve<ISurvey>; 
survey.Organization.Id := 5; 

и все это хорошо и прекрасно работает.

Теперь я хочу, чтобы создать класс-потомок для TSurvey:

type 
    TFieldSurvey = class (TSurvey) 
    ... 
end; 

И вопрос заключается в том, чтобы исправить экземпляр объекта для класса TFieldSurvey?

Если я использую Create(), то я получаю исключение:

fieldSurvey := TFieldSurvey.Create(); 
fieldSurvey.Organization.Id := 5 <- exception is here 

Должен ли я явно вызвать конструктор для области организации в TFieldSurvey конструктору, или есть другой способ? Например, используя GlobalContainer?

Заранее спасибо.

+0

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

+0

Я понимаю это сейчас, спасибо. – Aptem

ответ

4

Injection будет работать только при создании объекта через Контейнер, а не путем прямого вызова конструктора на вашем объекте. Поэтому вам нужно будет зарегистрировать TFieldSurvey с GlobalContainer, а затем позвонить Resolve, чтобы получить ваш объект.

Регистрация:

GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>('SPRING_SURVEY').InjectField ('_organization'); 
GlobalContainer.RegisterType<TFieldSurvey>.Implements<ISurvey>('SPRING_FIELD_SURVEY').InjectField ('_organization'); 

Тогда для получения экземпляра:

GlobalContainer.Resolve<ISurvey>('SPRING_FIELD_SURVEY') 

я добавил имена «SPRING_SURVEY» и «SPRING_FIELD_SURVEY», так как они оба реализовать ISurvey и это позволяет выбрать, какой класс экземпляр, который вы хотите, иначе вы закончите с последней реализацией, зарегистрированной для этого интерфейса. Если TFieldSurvey собирается реализовать свой собственный интерфейс (например, IFieldSurvey), вы можете покончить с именами, а затем приведите обратно к ISurvey, если необходимо.

Вы всегда можете использовать атрибут [Inject] тоже на поле _organization, а не с помощью .InjectField (после добавления Global.Container.Common ваших целей):

TSurvey = class (TInterfacedObject, ISurvey) 
    private 
    _id : Integer; 
    [Inject] 
    _organization : IOrganization; 

    function GetId() : Integer; 
    procedure SetId (const value : Integer); 

    function GetOrganization() : IOrganization; 
    procedure SetOrganization (const value : IOrganization); 

    public 
    property Id : Integer read GetId write SetId; 
    property Organization: IOrganization read GetOrganization write SetOrganization; 
    end; 

и ваша регистрация будет:

GlobalContainer.RegisterType<TSurvey>.Implements<ISurvey>('SPRING_SURVEY'); 
    GlobalContainer.RegisterType<TFieldSurvey>.Implements<ISurvey>('SPRING_FIELD_SURVEY'); 
+0

Джейсон, спасибо за объяснение. – Aptem

2

Вы не следует писать код таким образом, чтобы он работал только с контейнером DI.

Контейнер DI - это инструмент, и вам следует избегать зависимостей (прямо или косвенно) от него.

Это означает, что вам следует избегать использования полевой инъекции, потому что такой код не может работать с pure DI - вместо этого используйте конструктор или вложение свойств.

Также из фрагмента кода, который вы опубликовали, я чувствую запах service locator anti pattern.

Если вы хотите создать опрос, используйте заводскую съемку и введите его в класс, в котором вы его используете. Контейнеры DI обычно не предназначены для создания объектов ценности, и ваш класс опроса (несмотря на излишне наличие интерфейса) выглядит как один.

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

+0

Дорогой Стефан, спасибо за ваш комментарий. Можете ли вы привести несколько примеров, почему я не должен использовать контейнер DI таким образом? С какой точки зрения нужна эта инъекция? – Aptem

 Смежные вопросы

  • Нет связанных вопросов^_^