{"id":147,"date":"2014-01-28T18:59:35","date_gmt":"2014-01-28T07:59:35","guid":{"rendered":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/?p=147"},"modified":"2014-02-12T10:57:47","modified_gmt":"2014-02-11T23:57:47","slug":"introducing-the-sbd-dependency-injection-framework","status":"publish","type":"post","link":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/archives\/147","title":{"rendered":"Introducing the SBD Dependency Injection Framework"},"content":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/encrypted-tbn2.gstatic.com\/images?q=tbn:ANd9GcSVaHUKdIQsTYHhq_qInBeM54iQ6v7r_jY4NffsUeSWSvSinjGFeA\" alt=\"Happy\" \/><br \/>\nFrom today the Delphi community can leverage the power of the SBD Dependency Injection Framework. Oh happy developer!, you can find the source code at &#8230;<\/p>\n<ul>\n<li><a href=\"https:\/\/code.google.com\/p\/sbd-dependency-injection\/\" title=\"sbd-dependency-injection project on GoogleCode\" target=\"_blank\">https:\/\/code.google.com\/p\/sbd-dependency-injection\/<\/a><\/li>\n<\/ul>\n<p>&#8230; and download with a <a href=\"http:\/\/subversion.apache.org\/\" title=\"Subversion\" target=\"_blank\">Subversion<\/a> client.<\/p>\n<p>The SBD Dependency Injection Framework is &#8230; well &#8230; a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Dependency_injection\" title=\"DI\" target=\"_blank\">Dependency Injection<\/a> Framework for Delphi. It consists of two units accompanied by a demo program and fluff. The framework supports all versions of Delphi from 2010 onwards and all platforms and is available for use via the popular aqnd permissive <a href=\"http:\/\/en.wikipedia.org\/wiki\/Mozilla_Public_License\" title=\"MPL 2.0\" target=\"_blank\">MPL 2.0<\/a> license.<\/p>\n<h2>Features<\/h2>\n<p>For the sake of brevity, I will list only the main features of the framework.<\/p>\n<h3>Service oriented<\/h3>\n<p>The framework is Service oriented. In this context &#8220;Service&#8221; means a service accessed via an interface pointer with a defined API. Central to the framework is the Service Provider. The service provider is a service container for it&#8217;s clients. The service provider is also a service.<\/p>\n<h3>Usage is Attribute oriented<\/h3>\n<p>Yes, that&#8217;s right &#8211; the lazy developer can use attributes to specify automatic injection points. In other Injection Frameworks, the developer would have to write code support constructor injection. In SBD Injection Framework, auto-magical code-less injection of services occurs before the constructor is called, and is driven by the [Injection] attribute. <\/p>\n<h3>Example<\/h3>\n<p>First let&#8217;s start with a couple of service definitions &#8230;<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ntype\r\n  IBankAccount = interface\r\n  &#x5B;'{some guid}']\r\n    function Credit( Amount: currency; const Payee: string): boolean;\r\n    \/\/ Attempt to pay someone (Payee) something (Amount) from my bank account.\r\n    \/\/ Return True if payment was made.\r\n    end;\r\n\r\n  IProfitAndLossAccount = interface\r\n  &#x5B;'{some other guid}']\r\n    function DistributeDividend( GrossDividendToPayOut: double): boolean;\r\n    \/\/ Distribute the dividend to all the share-holders.\r\n    end;\r\n<\/pre>\n<p>Our task is to distribute a company&#8217;s profit to it&#8217;s shareholders, by implementing an instance of the IProfitAndLossAccount. We will assume that some-one else has already written a suitable IBankAccount service. Here is how we do it &#8230;.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ntype\r\n  TProfitAndLossAccount = class( TInterfacedObject, IProfitAndLossAccount)\r\n  private\r\n    &#x5B;Injection] FBankAccount: IBankAccount;\r\n    function DistributeDividend( GrossDividendToPayOut: double): boolean;\r\n  public\r\n    &#x5B;configuration] constructor ServiceModeCreate;\r\n  end;\r\n\r\nconstructor TProfitAndLossAccount.ServiceModeCreate;\r\nbegin\r\nend;  \/\/ Empty constructor! \r\n\r\nfunction TProfitAndLossAccount.DistributeDividend( GrossDividendToPayOut: double): boolean;\r\nbegin\r\n  \/\/ The two shareholders are Jack and Jill\r\n  result := FBankAccount.Credit( GrossDividendToPayOut \/ 2, 'Jack') and\r\n            FBankAccount.Credit( GrossDividendToPayOut \/ 2, 'Jill') and\r\nend;\r\n<\/pre>\n<p>Notice there is no constructor logic for the dependent service FBankAccount. A suitable service instance is inserted by the framework. If we have a service provider (ServiceProvider: IServiceProvider),<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nvar\r\n  PandL: IProfitAndLossAccount;\r\nbegin\r\nif ServiceProvider.Gn.Acquire&lt;IProfitAndLossAccount&gt;( PandL) then\r\n  PanL.DistributeDividend( 10000.0);\r\nend;\r\n<\/pre>\n<h3>Service implementation discrimination<\/h3>\n<p>If we have two different service definitions that just happen to use the same interface pointer type, but serve different purposes (not just different implementations serving the same purpose), the we can discriminate between the two with a &#8220;Configuration string&#8221;. This is what it looks like &#8230;<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\ntype\r\n  TProfitAndLossAccount = class( TInterfacedObject, IProfitAndLossAccount)\r\n  private\r\n    &#x5B;Injection] FBankAccount: IBankAccount;\r\n    function DistributeDividend( GrossDividendToPayOut: double): boolean;\r\n  public\r\n    &#x5B;configuration('accounting')] constructor ServiceModeCreate;\r\n  end;\r\n<\/pre>\n<p>Now this &#8230;<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nif ServiceProvider.Gn.Acquire&lt;IProfitAndLossAccount&gt;( PandL, 'accounting') then\r\n  PanL.DistributeDividend( 10000.0);\r\n<\/pre>\n<p>will use the above service implementation, but &#8230;<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nif ServiceProvider.Gn.Acquire&lt;IProfitAndLossAccount&gt;( PandL, 'something-else') then\r\n  PanL.DistributeDividend( 10000.0);\r\n... will not.\r\n<\/pre>\n<h3>Competing service array versus co-operative service array<\/h3>\n<p>You can register an array (&#8220;Service file&#8221;) of alternate implementations of the one service definition (Interface pointer type, guid + config string). In other frameworks you can only register one implementation per service definition, if you can do multiple, then the service file can only be used competitively (that is to say the client asks for a service instance, and the provider gives one). SBD Dependency Injection framework can offer a file of service implementations either competitively or co-operatively.<\/p>\n<p>Imagine a task of compressing a message. The service definition is &#8220;compress this data&#8221;. There is lots of ways to compress data. You might have many algorithms at your disposal in the form of registered services. You pick one, acquire an instance from the service provider and solve your problem. That is an example of a competitive service array.<\/p>\n<p><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/seo-takeover.com\/wp-content\/uploads\/2013\/09\/competition.png?resize=380%2C316\" alt=\"Competing\" width=\"380\" height=\"316\"\/> <em>versus<\/em> <img data-recalc-dims=\"1\" decoding=\"async\" src=\"http:\/\/europamedia.files.wordpress.com\/2011\/05\/cooperation-international2.jpg?w=640\" alt=\"Cooperating\" \/><br \/>\nBut what about the reverse problem of de-compression, where a standard has not been followed. You need to find the correct compressor to correctly decompress it. As the selection of compressor was not recorded, you really need to get all the decompressor services in stock to examine the compressed data, just to see which one is the one to use. Now you are using an array of service implementations in a co-operative fashion.<\/p>\n<p>Some hard problems can be simplified by leveraging a co-operative array of services. SBD Injection framework, makes acquisition and usage of co-operative services easy and almost code-free. When you acquire co-operative services, instead of one selected service being injected, you get a collection of them. At service registration time, you can define how the collection is made and how it is added to &#8211; or just use IInterfaceList.<\/p>\n<h3>Documentation<\/h3>\n<p>The documentation will be in form of a demo program, some wiki pages of text (like this blog post), and some Help Insight \/\/\/&lt;summary&gt; notes. This is a work-in-progress. At the moment, I have done about 30% of the demo.<\/p>\n<aside style=\"width:300px; background-color:green;\" class=\"sbd-aside sbd-right sbd-round\"><header class=\"sbd-header\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/seanbdurkin.id.au\/pascaliburnus2\/wp-content\/plugins\/sbd-aside\/expand.gif?resize=13%2C14\" width=\"13\" height=\"14\" border=\"0\"\n alt=\"Show\/Hide\" title=\"Show\/Hide\"\n onclick=\"togglePannel(this)\"\/>Using it?<\/header> <div class=\"sbd-hidden sbd-tight\"><hr class=\"sbd-swish\"\/><span class=\"sbd-content\">\n<p>The copying permission is defined by the MPL 2.0 license. It would also be nice if you posted a comment on this entry.<br \/>\n<\/span><\/div><\/aside>\n<h3>No singletons<\/h3>\n<p>The framework does not define singletons, nor require you to use them. Nice!<\/p>\n<h3>But how does it compare to the DI in Delphi-Spring?<\/h3>\n<p>I don&#8217;t know. Perhaps you can tell me?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>From today the Delphi community can leverage the power of the SBD Dependency Injection Framework. Oh happy developer!, you can find the source code at &#8230; https:\/\/code.google.com\/p\/sbd-dependency-injection\/ &#8230; and download with a Subversion client. The SBD Dependency Injection Framework is &hellip; <a href=\"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/archives\/147\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[10],"tags":[11],"class_list":["post-147","post","type-post","status-publish","format-standard","hentry","category-delphi","tag-dependency-injection"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p2QXbt-2n","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/posts\/147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/comments?post=147"}],"version-history":[{"count":16,"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/posts\/147\/revisions"}],"predecessor-version":[{"id":164,"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/posts\/147\/revisions\/164"}],"wp:attachment":[{"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/media?parent=147"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/categories?post=147"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/seanbdurkin.id.au\/pascaliburnus2\/wp-json\/wp\/v2\/tags?post=147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}