[Lazarus] Inversion of control (IoC) and Dependency injection (DI)

silvioprog silvioprog at gmail.com
Sun Jan 11 21:12:03 CET 2015


On Mon, Jan 5, 2015 at 5:07 PM, luiz americo pereira camara <
luizmed at oi.com.br> wrote:

> Starting a new thread.
>
> 2015-01-05 15:16 GMT-03:00 silvioprog <silvioprog at gmail.com>:
>
>> On Mon, Jan 5, 2015 at 12:54 PM, Marco van de Voort <marcov at stack.nl>
>> wrote:
>>
>>>
>>> As a first step in the 3.0.0 release process the stable branch was
>>> branched
>>> off to branches/fixes_3_0 and the version number was updated to 3.0.1
>>>
>>> The version in trunk was raised to 3.1.1
>>>
>>> Scripts might need modification accordingly.
>>
>>
>> Good news!
>>
>> Chances of custom attributes[1] (or something like this) in release 3.0?
>> I have plans to use IoC[2] and DI using this feature.
>>
>>
> I created a IoC Container that can be found at
> https://code.google.com/p/luipack/source/browse/trunk/luicomponents/luiioccontainer.pas
> . It has no dependencies.
>

Awesome!

With it is possible to implement Service Locator and Property Injection
> patterns. Constructor Injection is not possible due to lacking of Extended
> RTTI support in fpc.
>

Can you send a small (and isolated) sample showing how to use it?


> While the C# crowd  praises the Constructor Injection pattern (
> http://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container
> ), i had hard times figuring how it would work in real world / Lazarus
> projects. Also, polluting the constructor  signature is not something that
> i like. And finally with Constructor Injection is not possible to use with
> TComponent / TForm
>
> So in the end, i use the service locator and have plans to use Property
> Injection pattern
>
> BTW: Custom Attributes support would help to have a nicer Property
> Injection implementation
>

I've plan to use something like this (CDI inspirations: http://cdi-spec.org
):

The model:

uses
  My.Company.MySDK.EntityAttributes, My.Company.MySDK.TableAttributes ...;
type
  [Entity]
  [Table('products')]
  TProduct = class(TObject)
  public
    [Id][GeneratedValue]
    property Id: LongInt ...;
    [ManyToOne][JoinColumn('OrderId')]
    property OrderId: LontInt ...;
    [NotNull][NotEmpty][Size(1, 10)][Unique]
    property Name: String ...;
    [Nulls][Lenght(100)][Unique]
    property Description: String ...;
    [MyCustomCurrConversion(TypeInfo(Currency), TypeInfo(String), ',0.00')]
    [MyCustomMinMax('Price must be >= %d and <= %d.', [1, 1000])]
    property Price: Currency ...;
  end;


The DAO:

type
  [RequestScoped]
  TProductDao = class(TObject)
  private
    [Inject] property Session: TSession ... ;
    [Transational] procedure Add(AProduct: TProduct);
    ...
  end;
...procedure TProductDao.Add(AProduct: TProduct);begin
  Session.Save(AProduct);end;


The *produces* (to use external libs like *JCore*):

type
  [ApplicationScoped]
  TSessionCreator = class(TObject)
  private
    [Inject] property SessionFactory: TJCoreSession ... ;
    [Produces] function GetSession: TSession;
...
  end;
...
TSessionCreator.GetSession: TSession;begin
  Result := ASessionFactory.OpenSession;end;

TSessionCreator.Close([Disposes]ASession: TSession) {begin  if
ASession.IsOpen    ASession.Close;end;


The controller:

uses
  My.Company.ControllerAttributes ... ;
type
  [Controller]
  TProcuctController = class(TObject)
  public
    [Post][Transational] procedure Add([Valid] AProduct: TProduct); //
[Valid]: to validade properties
    [Get][Path('./product')][Transational] procedure
List([Pagination('page={[0-9]}&rows={[0-9]}')] AProducts:
TArrayList<TProduct>); // to paginate products
    [Inject] property ProductDao: TProductDao ...; // inject DAO
    [Inject] property Result: TResponse ...; // inject Response
  end;
...
procedure TProcuctController.Add(AProduct: TProduct);begin
  ProductDao.Add(AProduct);
  Result.SetAttribute(AProduct,
'product').RedirectTo(TProductController).List;end;
procedure TProcuctController.List(AProducts: TArrayList<TProduct>);begin
  Result.SetAttribute(AProducts, 'products'); // to create a variable
"products" in my BSP viewend;


The view:

<html>
<ul>
<c:forEach items="${products}" var="product">
    <li> ${product.name} - <fmt:currency value="${product.price}"
mask="R$ ,0.00"/></li>
</c:forEach>
</ul>
</html>


But I think that I'll still wait some years to make it possible in Free
Pascal hehe ...

-- 
Silvio Clécio
My public projects - github.com/silvioprog
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.lazarus-ide.org/pipermail/lazarus/attachments/20150111/e7269c03/attachment-0003.html>


More information about the Lazarus mailing list