Original in Russian: http://programmingmindstream.blogspot.ru/2015/03/blog-post_12.html
Lately I’ve been shaking up our libraries for correcting of dependences.
The libraries contain several millions of code lines and several thousands of modules.
They are used in several tens of programming projects developed by fairly large number of programmers teams.
That is not an “idle talk”.
For long time we have written:
1. Our own word processing application on a level of Word 97.
2. Our own implementation of IStorage, which is more effective than from MS.
3. Our own full-text indexer.
4. DUnit add-ins (in Russian).
5. Our own script engine (FORTH-like) on the level of Python.
6. Our own implementation of GUI-cases testing in “natural language”.
7. Our own rendering of RTF-like documents for iOS.
8. Our own implementation of SAX and DOM paradigms.
9. Our own code generation from UML.
10. Our own implementation of MVC-like framework.
The dependences are shown only by drawing of this staff on UML and, subsequently, validation of relations and cycles as well as code generation.
I’ve already used the simple “dependency inversion” more than once.
I really like it.
I developed such a liking for it that I even made a separate code generation pattern for this staff.
I’ll give an example – WITHOUT code generation pattern, in BASE primitives.
It looks something like this:
Previously:
A call B.method
A was connected to B,
Now:
A call C.method
B implements C.method
A is connected to C.
B is connected to C.
A has “no idea” of B.
B has “no idea” of A, too.
A knows about C.
B knows about C.
С is a “service” enabling behavior substitution.
The diagram:
The code:
Injection point:
The injection:
Actually, this approach is used by Embarcadero in FMX.
They call it Services.
Sure, with a true Service-Locator.
It is more SIMPLE in NON-BASE primitives. But I’ll write about it edit next time, if you are interested.
For those who like to “nit-pick through spaces and commas” – I’ll STRESS it is only an IDEA, not a guide to action.
Naturally, I’ve already given a link to Spring For Delphi.
My colleague also wrote about it – The colleague wrote. Example of Dependency Injection (in Russian).
Some more (in Russian):
Link. Taking stock of dependency inversion principle
Link. Dependency inversion principle
A similar problem was discussed here – About tests and specially-fitted “check points”
Lately I’ve been shaking up our libraries for correcting of dependences.
The libraries contain several millions of code lines and several thousands of modules.
They are used in several tens of programming projects developed by fairly large number of programmers teams.
That is not an “idle talk”.
For long time we have written:
1. Our own word processing application on a level of Word 97.
2. Our own implementation of IStorage, which is more effective than from MS.
3. Our own full-text indexer.
4. DUnit add-ins (in Russian).
5. Our own script engine (FORTH-like) on the level of Python.
6. Our own implementation of GUI-cases testing in “natural language”.
7. Our own rendering of RTF-like documents for iOS.
8. Our own implementation of SAX and DOM paradigms.
9. Our own code generation from UML.
10. Our own implementation of MVC-like framework.
The dependences are shown only by drawing of this staff on UML and, subsequently, validation of relations and cycles as well as code generation.
I’ve already used the simple “dependency inversion” more than once.
I really like it.
I developed such a liking for it that I even made a separate code generation pattern for this staff.
I’ll give an example – WITHOUT code generation pattern, in BASE primitives.
It looks something like this:
Previously:
A call B.method
A was connected to B,
Now:
A call C.method
B implements C.method
A is connected to C.
B is connected to C.
A has “no idea” of B.
B has “no idea” of A, too.
A knows about C.
B knows about C.
С is a “service” enabling behavior substitution.
The diagram:
The code:
Injection point:
unit l3DispatcherHelper; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // The library "L3$AFW" // The unit: "w:/common/components/rtl/Garant/L3/l3DispatcherHelper.pas" // Native Delphi interfaces (.pas) // Generated from UML model, root element: SimpleClass::Class Shared Delphi Low Level::L3$AFW::VCMHelpers::Tl3DispatcherHelper // // //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ! Completely generated from the model. It is not allowed to edit manually. ! {$Include ..\L3\l3Define.inc} interface uses l3ProtoObject ; (* Ml3DispatcherHelper = PureMixIn procedure ClearHistory; end;//Ml3DispatcherHelper *) type Il3DispatcherHelper = interface(IUnknown) ['{41B8F325-9AFB-447E-B3E7-2C433912BC2A}'] // Ml3DispatcherHelper procedure ClearHistory; end;//Il3DispatcherHelper Tl3DispatcherHelper = class(Tl3ProtoObject) private // private fields f_Alien : Il3DispatcherHelper; public // realized methods procedure ClearHistory; protected // overridden protected methods procedure ClearFields; override; {* Signature of ClearFields method } public // public methods procedure SetAlienHelper(const anAlien: Il3DispatcherHelper); class function Exists: Boolean; {* We check if singleton instance has been created } public // singleton factory method class function Instance: Tl3DispatcherHelper; {- returns the singleton instance. } end;//Tl3DispatcherHelper implementation uses l3Base {a} ; // start class Tl3DispatcherHelper var g_Tl3DispatcherHelper : Tl3DispatcherHelper = nil; procedure Tl3DispatcherHelperFree; begin l3Free(g_Tl3DispatcherHelper); end; class function Tl3DispatcherHelper.Instance: Tl3DispatcherHelper; begin if (g_Tl3DispatcherHelper = nil) then begin l3System.AddExitProc(Tl3DispatcherHelperFree); g_Tl3DispatcherHelper := Create; end; Result := g_Tl3DispatcherHelper; end; procedure Tl3DispatcherHelper.SetAlienHelper(const anAlien: Il3DispatcherHelper); //#UC START# *5501A41602E7_5501A3AE02AA_var* //#UC END# *5501A41602E7_5501A3AE02AA_var* begin //#UC START# *5501A41602E7_5501A3AE02AA_impl* Assert(f_Alien = nil); f_Alien := anAlien; //#UC END# *5501A41602E7_5501A3AE02AA_impl* end;//Tl3DispatcherHelper.SetAlienHelper class function Tl3DispatcherHelper.Exists: Boolean; {-} begin Result := g_Tl3DispatcherHelper <> nil; end;//Tl3DispatcherHelper.Exists procedure Tl3DispatcherHelper.ClearHistory; //#UC START# *5501A435019E_5501A3AE02AA_var* //#UC END# *5501A435019E_5501A3AE02AA_var* begin //#UC START# *5501A435019E_5501A3AE02AA_impl* if (f_Alien <> nil) then f_Alien.ClearHistory; //#UC END# *5501A435019E_5501A3AE02AA_impl* end;//Tl3DispatcherHelper.ClearHistory procedure Tl3DispatcherHelper.ClearFields; {-} begin f_Alien := nil; inherited; end;//Tl3DispatcherHelper.ClearFields end.
The injection:
TvcmDispatcherHelper = class(Tl3ProtoObject, Il3DispatcherHelper) public // realized methods procedure ClearHistory; public // public methods class function Exists: Boolean; {* We check if singleton instant has been created } public // singleton factory method class function Instance: TvcmDispatcherHelper; {- returns the singleton instance. } end;//TvcmDispatcherHelper ... // start class TvcmDispatcherHelper var g_TvcmDispatcherHelper : TvcmDispatcherHelper = nil; procedure TvcmDispatcherHelperFree; begin l3Free(g_TvcmDispatcherHelper); end; class function TvcmDispatcherHelper.Instance: TvcmDispatcherHelper; begin if (g_TvcmDispatcherHelper = nil) then begin l3System.AddExitProc(TvcmDispatcherHelperFree); g_TvcmDispatcherHelper := Create; end; Result := g_TvcmDispatcherHelper; end; class function TvcmDispatcherHelper.Exists: Boolean; {-} begin Result := g_TvcmDispatcherHelper <> nil; end;//TvcmDispatcherHelper.Exists procedure TvcmDispatcherHelper.ClearHistory; //#UC START# *5501A435019E_5501A60D002E_var* //#UC END# *5501A435019E_5501A60D002E_var* begin //#UC START# *5501A435019E_5501A60D002E_impl* if (vcmDispatcher <> nil) then if (vcmDispatcher.History <> nil) then vcmDispatcher.History.Clear(false); //#UC END# *5501A435019E_5501A60D002E_impl* end;//TvcmDispatcherHelper.ClearHistory ... Tl3DispatcherHelper.Instance.SetAlienHelper(TvcmDispatcherHelper.Instance); ...
Actually, this approach is used by Embarcadero in FMX.
They call it Services.
Sure, with a true Service-Locator.
It is more SIMPLE in NON-BASE primitives. But I’ll write about it edit next time, if you are interested.
For those who like to “nit-pick through spaces and commas” – I’ll STRESS it is only an IDEA, not a guide to action.
Naturally, I’ve already given a link to Spring For Delphi.
My colleague also wrote about it – The colleague wrote. Example of Dependency Injection (in Russian).
Some more (in Russian):
Link. Taking stock of dependency inversion principle
Link. Dependency inversion principle
A similar problem was discussed here – About tests and specially-fitted “check points”
Комментариев нет:
Отправить комментарий