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”


Комментариев нет:
Отправить комментарий