Original in Russian:
http://programmingmindstream.blogspot.com/2015/03/blog-post_73.html
Again about dependency inversion.
The source code was here –
Briefly. Shooting the breeze. Dependency Inversion.
Two diagrams were there:
Diagram 1:
Diagram 2:
I “conjured” over patterns generation a bit, and the diagrams became like this:
Diagram 1:
- virtually, we define DispatcherHelper service.
Diagram 2:
- we define one of the implementations of DispatcherHelper service named TvcmDispatcherHelper.
The code remains the SAME.
Patterns implementation:
: ServicePrim::Class
= SimpleClass::Class
// Functions of stereotype
%f _st_space_key
SHD
%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BA9C0354*
//#UC END# *5502C6A200F5for5502BA9C0354*
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BA9C0354*
//#UC END# *5502CBD4031Efor5502BA9C0354*
// Inherited implementation
// overriding of base stereotype Delphi interfaces and implementation::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BA9C0354*
[{%Gx!=true}\
[{"%{Tl3ProtoObject}N"=""}%f_find_element(Tl3ProtoObject,Tl3ProtoObject)]\
%S%f_make_accessable(%{Tl3ProtoObject}U)\
%S%f_add_inheritable(%{Tl3ProtoObject}U)\
]\
%S%f_set_up(singleton,true)\
%S%f_BeforeClassSpell()\
%S%[inherited]\
%S%f_AfterClassSpell()
//#UC END# *4B2A19E3038Bfor5502BA9C0354*
: Service::Class
? Service
= ServicePrim::Class
// Parameters of stereotype
a f
/ - abstraction type
// Functions of stereotype
%f _st_space_key
SHD
%f _CheckMixin
//#UC START# *5502CBF50065for5502BABC0193*
[{"%S%{Mixin}N"=""}\
<{}{%C#f_IsPureMixIn()=true&"%CN"="M%f_cut_prefix(%f_pas_TypeName(%S),T)"}\
%S%f_set_var(Mixin,C)\
// %f_cycle_break(%S)\
>\
]
//#UC END# *5502CBF50065for5502BABC0193*
%f _CheckFacet
//#UC START# *5502CC07027Efor5502BABC0193*
[{"%S%{Facet}N"=""}\
<{}{%t_interface(%C)=true&"%CN"="I%f_cut_prefix(%f_pas_TypeName(%S),T)"}\
%S%f_set_var(Facet,C)\
// %f_cycle_break(%S)\
>\
]
//#UC END# *5502CC07027Efor5502BABC0193*
// Inherited implementation
// overriding of base stereotype Delphi interfaces and implementation::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BABC0193*
%S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BABC0193*
// overriding of base stereotype ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BABC0193*
%S%[inherited]
//#UC END# *5502CBD4031Efor5502BABC0193*
// overriding of base stereotype ServicePrim::Class
%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BABC0193*
%S%f_CheckMixin()\
%S%f_CheckFacet()\
// %f_warning(Mixin: %S%{Mixin}N)\
// %f_warning(Facet: %S%{Facet}N)\
[{"%S%{Facet}N"=""}\
%S%f_add_class(%SU_Facet,Facet,I%f_cut_prefix(%f_pas_TypeName(%S),T),Facet_Inst)\
%{Facet_Inst}%f_set_documentation(Interface of service %SN)\
%S%f_set_var(Facet,{Facet_Inst})\
]\
%S%f_add_realized(%S%{Mixin}U)\
%S%{Facet}%f_add_realized(%S%{Mixin}U)\
%S%f_add_attribute(%SU_%S%{Facet}U_Alien,writeonly,Alien : %S%{Facet}U,Attr_Inst)\
%{Attr_Inst}%f_set_link_type(ref)\
%{Attr_Inst}%f_set_up(pm,true)\
%{Attr_Inst}%f_set_up(needs field,true)\
%{Attr_Inst}%f_set_visibility_type(PublicAccess)\
%{Attr_Inst}%f_set_abstraction_type(final)\
%{Attr_Inst}%f_set_documentation(External service implementation %S%{Facet}N)\
%{Attr_Inst}%f_set_uc_content(intf.pas,_%f_pas_MethodOwnerID(%{Attr_Inst},%S)set_var,\
{-}\
)\
%{Attr_Inst}%f_set_uc_content(intf.pas,_%f_pas_MethodOwnerID(%{Attr_Inst},%S)set_impl,\
Assert((f_Alien = nil) OR (aValue = nil));
f_Alien := aValue;\
)\
%f_DoSpellField(%{Attr_Inst})\
// %f_warning(%SN need cleanup: %S%f_NeedCleanupFields())\
%S%[inherited]
//#UC END# *5502C6A200F5for5502BABC0193*
// Nested stereotypes
: Service::Class::responsibility::Operation
? Responsibility
= ClassBase::Class::Operation
// Parameters of stereotype
v +
/ - visibility types
a f
/ - abstraction type
T
/ - can have no “purpose” (type/result)
m f
/ - can be not implemented/have overridden implementation
// Generators
// Model generation in MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BBDB02C9*
//#UC END# *46E6D4BB0339for5502BBDB02C9*
// generator of interface factories implementation in java (.java)
+ fctr.java
//#UC START# *470321C1038Afor5502BBDB02C9*
//#UC END# *470321C1038Afor5502BBDB02C9*
// The second interface stereotype section, for example, class properties implementation.
+ intf2.pas
R
//#UC START# *477398E501C0for5502BBDB02C9*
//#UC END# *477398E501C0for5502BBDB02C9*
// The third interface section, for example, properties field.
+ intf3.pas
R
//#UC START# *4774D2A20372for5502BBDB02C9*
//#UC END# *4774D2A20372for5502BBDB02C9*
// Forms files generator (.dfm)
+ dfm
R
//#UC START# *49F5795900ECfor5502BBDB02C9*
//#UC END# *49F5795900ECfor5502BBDB02C9*
// // TestComplete Scripts(.sd)
+ sd
R
//#UC START# *4DE79AFC0030for5502BBDB02C9*
//#UC END# *4DE79AFC0030for5502BBDB02C9*
// Hack for [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BBDB02C9*
//#UC END# *4E65F581015Afor5502BBDB02C9*
// Native Delphi interfaces (.pas)
+ intf.pas
R
//#UC START# *470F1571031Cfor5502BBDB02C9*
//#UC END# *470F1571031Cfor5502BBDB02C9*
// Implementation in Delphi(.pas)
+ impl.pas
R
//#UC START# *470F15B800CBfor5502BBDB02C9*
//#UC END# *470F15B800CBfor5502BBDB02C9*
// Functions of stereotype
%f _st_space_key
SHD
// Inherited implementation
// implementation of abstract stereotype Documentation::MDAGenerator
// prints the description of wiki methods
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BBDB02C9*
//#UC END# *470484D50138for5502BBDB02C9*
: ServiceImplementation::Class
? Service implementation
= ServicePrim::Class
// Parameters of stereotype
a f
/ - abstraction type
// Functions of stereotype
%f _st_space_key
SHD
// Inherited implementation
// overriding of base stereotype Delphi interfaces and implementation::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BADD01CB*
%S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BADD01CB*
// overriding of base stereotype ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
%S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*
// overriding of base stereotype ServicePrim::Class
%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BADD01CB*
<{}{%CC=Dependency&%CS=implements}\
%C%T#f_CheckFacet()\
// %f_warning(%C%TN)\
// %f_warning(%C%T%{Facet}N)\
// %f_warning(%C%T%{Facet}U)\
[{"%C%T%{Facet}N"!=""}\
%S%f_make_accessable(%C%T%{Facet}U)\
%S%f_add_realized(%C%T%{Facet}U)\
]\
>\
%S%f_add_operation(%SU_Ini_Reg_Class,ini,bind (),Op_Instance)\
%{Op_Instance}%f_set_documentation(registration %SN)\
%{Op_Instance}%f_set_abstraction_type(final)\
%{Op_Instance}%f_set_visibility_type(PrivateAccess)\
%{Op_Instance}%f_set_uc_content(intf.pas,,\
<{\n}{%CC=Dependency&%CS=implements}\
%f_pas_TypeName(%C%T).Instance.Alien := %f_pas_TypeName(%S).Instance;\
>\
)\
%S%[inherited]
//#UC END# *5502C6A200F5for5502BADD01CB*
// Nested stereotypes
: ServiceImplementation::Class::implements::ClassDependency
? Specifying of implementation
= Delphi interfaces and implementation::MDAGenerator
// Generators
// Model generation in MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BC8E029A*
//#UC END# *46E6D4BB0339for5502BC8E029A*
// Native Delphi interfaces (.pas)
+ intf.pas
R
//#UC START# *470F1571031Cfor5502BC8E029A*
//#UC END# *470F1571031Cfor5502BC8E029A*
// Implementation in Delphi(.pas)
+ impl.pas
R
//#UC START# *470F15B800CBfor5502BC8E029A*
//#UC END# *470F15B800CBfor5502BC8E029A*
// The second interface stereotype section, for example, class properties implementation.
+ intf2.pas
R
//#UC START# *477398E501C0for5502BC8E029A*
//#UC END# *477398E501C0for5502BC8E029A*
// The third interface section, for example, properties field.
+ intf3.pas
R
//#UC START# *4774D2A20372for5502BC8E029A*
//#UC END# *4774D2A20372for5502BC8E029A*
// Forms files generator (.dfm)
+ dfm
R
//#UC START# *49F5795900ECfor5502BC8E029A*
//#UC END# *49F5795900ECfor5502BC8E029A*
// TestComplete Scripts(.sd)
+ sd
R
//#UC START# *4DE79AFC0030for5502BC8E029A*
//#UC END# *4DE79AFC0030for5502BC8E029A*
// Hack for [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BC8E029A*
//#UC END# *4E65F581015Afor5502BC8E029A*
// Functions of stereotype
%f _st_space_key
SHD
// Inherited implementation
// implementation of abstract stereotype Documentation::MDAGenerator
// check of elements constraints
%t _constraint
//#UC START# *4704C0E30186for5502BC8E029A*
c {}
r {""=""}: {}
//#UC END# *4704C0E30186for5502BC8E029A*
// implementation of abstract stereotype Documentation::MDAGenerator
// prints the description of element (operation, attribute) in wiki
%f _wiki_child_kind
//#UC START# *4705CBD6003Efor5502BC8E029A*
//#UC END# *4705CBD6003Efor5502BC8E029A*
// implementation of abstract stereotype Documentation::MDAGenerator
// prints the description of auto-generated methods in wiki
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BC8E029A*
//#UC END# *470484D50138for5502BC8E029A*
“Gobbledygook” patterns look bone chilling. However, they are written “for good” and can possibly be used many times.
A small legend:
%S - is Self.
\ - is ;
%P – parent element.
%G – base classes.
%R – implemented interfaces.
%T - expression type.
%C – child elements.
%CN – child element name. Usually - Child.Name.
%CS - child element stereotype name.
%S%{Facet} – field value (member) from Self. Usually - Self.Facet.
%f _Name – Declaration of current stereotype function called Name (class method).
f _Name – free function declaration.
%t _constraint –declaration of current stereotype transformer named “constraint”. Analogue of the Case.
: ServiceImplementation::Class – declares ServiceImplementation stereotype.
= ServicePrim::Class – inherits it from ServicePrim.
? Service implementation - specifies documentation for the current element.
The cycle:
<{}{%CS=Dependency}%CN>
// - looks through the child elements that represent dependences and prints their names (%CN)
<{}{%t_simple_class(%P)=true}%PN>
// - looks through the parent elements that are “simple classes” and prints their names (%PN)
Operator if:
[{"%S%{Mixin}N"=""}\
<{}{%C#f_IsPureMixIn()=true}\
%S%f_set_var(Mixin,C)>\
]
// - if Self.Mixin.Name = ''
// for C in Self.Children (if C.IsPureMixIn) do
// Self.Mixin := C
// i.e. if Self.Mixin has not been set, we look through the childs for PureMixIn
Stereotype method:
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
%S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*
// procedure Service.AfterClassSpell; override;
//begin
// inherited;
//end;
At least 10-20 of
already written classes will be changed under this paradigm. I am terribly bored with parasite cross-dependences between the libraries.
Why do “parasite” cross-dependences actually appear?
This is not because one doesn’t know about
dependency inversion principle.
The reason is he is often not enthusiastic about “all this staff”
It is more simple to write “one more uses”.
Sometimes one simply doesn’t know that changes he makes can influence the concurrent projects.
This is normal.
Instead, when parasite dependences are revealed, they are dealt with “in two clicks”.