вторник, 14 апреля 2015 г.

Коротко. Продолжение про инверсию зависимостей

Продолжение про инверсию зависимостей.

Исходный пост был тут - Коротко. Ни о чём. Инверсия зависимостей.

Там были две диаграммы:

Диаграмма 1:


Диаграмма 2:

Я немного "поколдовал" над шаблонами генерации и диаграммы стали такими:

Диаграмма 1:

- тут мы фактически определяем сервис DispatcherHelper.

Диаграмма 2:
- тут мы определяем одну из реализаций сервиса DispatcherHelper. С именем TvcmDispatcherHelper.

Код остался ТЕМ ЖЕ.

Реализация шаблонов:

: ServicePrim::Class
= SimpleClass::Class

// Функции стереотипа

%f _st_space_key
 SHD

%f _BeforeClassSpell
//#UC START# *5502C6A200F5for5502BA9C0354*
//#UC END# *5502C6A200F5for5502BA9C0354*

%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BA9C0354*
//#UC END# *5502CBD4031Efor5502BA9C0354*

// Унаследованная реализация

// перекрытие базового стереотипа Delphi интерфейсы и реализация::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
? Сервис
= ServicePrim::Class

// Параметры стереотипа
a f
/ - тип абстракции

// Функции стереотипа

%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*

// Унаследованная реализация

// перекрытие базового стереотипа Delphi интерфейсы и реализация::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BABC0193*
 %S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BABC0193*

// перекрытие базового стереотипа ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BABC0193*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BABC0193*

// перекрытие базового стереотипа 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(Интерфейс сервиса %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(Внешняя реализация сервиса %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*

// Вложенные стереотипы

: Service::Class::responsibility::Operation
? Ответственность
= ClassBase::Class::Operation

// Параметры стереотипа
v +
/ - типы видимости
a f
/ - тип абстракции
T 
/ - может не иметь "цели" (типа/результата)
m f
/ - не может быть реализован/иметь перекрытую реализацию

// Генераторы
// Генерация модели в MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BBDB02C9*
//#UC END# *46E6D4BB0339for5502BBDB02C9*

// генератор реализации фабрик интерфейсов на java (.java)
+ fctr.java
//#UC START# *470321C1038Afor5502BBDB02C9*
//#UC END# *470321C1038Afor5502BBDB02C9*

// Вторая интерфейсная секция стереотипа. Например реализация свойств класса.
+ intf2.pas
R  
//#UC START# *477398E501C0for5502BBDB02C9*
//#UC END# *477398E501C0for5502BBDB02C9*

// 3-я секция интерфейса. Например поле для свойства.
+ intf3.pas
R  
//#UC START# *4774D2A20372for5502BBDB02C9*
//#UC END# *4774D2A20372for5502BBDB02C9*

// Генератор файлов форм (.dfm)
+ dfm
R  
//#UC START# *49F5795900ECfor5502BBDB02C9*
//#UC END# *49F5795900ECfor5502BBDB02C9*

// Скрипты TC (.sd)
+ sd
R  
//#UC START# *4DE79AFC0030for5502BBDB02C9*
//#UC END# *4DE79AFC0030for5502BBDB02C9*

// Хак для [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BBDB02C9*
//#UC END# *4E65F581015Afor5502BBDB02C9*

// Родные Delphi интерфейсы (.pas)
+ intf.pas
R  
//#UC START# *470F1571031Cfor5502BBDB02C9*
//#UC END# *470F1571031Cfor5502BBDB02C9*

// Реализация на Delphi(.pas)
+ impl.pas
R  
//#UC START# *470F15B800CBfor5502BBDB02C9*
//#UC END# *470F15B800CBfor5502BBDB02C9*

// Функции стереотипа
%f _st_space_key
 SHD

// Унаследованная реализация

// реализация абстрактного стереотипа Документация::MDAGenerator
// вывод описание авто-генерируемых методов в wiki
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BBDB02C9*
//#UC END# *470484D50138for5502BBDB02C9*


: ServiceImplementation::Class
? Реализация сервиса
= ServicePrim::Class

// Параметры стереотипа
a f
/ - тип абстракции

// Функции стереотипа

%f _st_space_key
 SHD

// Унаследованная реализация

// перекрытие базового стереотипа Delphi интерфейсы и реализация::MDAGenerator
%f _DoSpell
//#UC START# *4B2A19E3038Bfor5502BADD01CB*
 %S%[inherited]
//#UC END# *4B2A19E3038Bfor5502BADD01CB*

// перекрытие базового стереотипа ServicePrim::Class
%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*

// перекрытие базового стереотипа 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(Регистрация %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*

// Вложенные стереотипы

: ServiceImplementation::Class::implements::ClassDependency
? Указание, что реализуется
= Delphi интерфейсы и реализация::MDAGenerator

// Генераторы
// Генерация модели в MDKnow
+ wiki
//#UC START# *46E6D4BB0339for5502BC8E029A*
//#UC END# *46E6D4BB0339for5502BC8E029A*

// Родные Delphi интерфейсы (.pas)
+ intf.pas
R  
//#UC START# *470F1571031Cfor5502BC8E029A*
//#UC END# *470F1571031Cfor5502BC8E029A*

// Реализация на Delphi(.pas)
+ impl.pas
R  
//#UC START# *470F15B800CBfor5502BC8E029A*
//#UC END# *470F15B800CBfor5502BC8E029A*

// Вторая интерфейсная секция стереотипа. Например реализация свойств класса.
+ intf2.pas
R  
//#UC START# *477398E501C0for5502BC8E029A*
//#UC END# *477398E501C0for5502BC8E029A*

// 3-я секция интерфейса. Например поле для свойства.
+ intf3.pas
R  
//#UC START# *4774D2A20372for5502BC8E029A*
//#UC END# *4774D2A20372for5502BC8E029A*

// Генератор файлов форм (.dfm)
+ dfm
R  
//#UC START# *49F5795900ECfor5502BC8E029A*
//#UC END# *49F5795900ECfor5502BC8E029A*

// Скрипты TC (.sd)
+ sd
R  
//#UC START# *4DE79AFC0030for5502BC8E029A*
//#UC END# *4DE79AFC0030for5502BC8E029A*

// Хак для [$281531116]
+ link_to_requests_hack
//#UC START# *4E65F581015Afor5502BC8E029A*
//#UC END# *4E65F581015Afor5502BC8E029A*

// Функции стереотипа
%f _st_space_key
 SHD

// Унаследованная реализация

// реализация абстрактного стереотипа Документация::MDAGenerator
// проверка ограничений накладываемых на элемент
%t _constraint
//#UC START# *4704C0E30186for5502BC8E029A*
c          {}
r {""=""}: {}
//#UC END# *4704C0E30186for5502BC8E029A*

// реализация абстрактного стереотипа Документация::MDAGenerator
// выводит описание элемента (операция, атрибут) в wiki
%f _wiki_child_kind
//#UC START# *4705CBD6003Efor5502BC8E029A*
//#UC END# *4705CBD6003Efor5502BC8E029A*

// реализация абстрактного стереотипа Документация::MDAGenerator
// вывод описание авто-генерируемых методов в wiki
%f _wiki_up_add_gen
//#UC START# *470484D50138for5502BC8E029A*
//#UC END# *470484D50138for5502BC8E029A*


Шаблоны "на птичьем языке" выглядят конечно устрашающе. Но зато написаны "раз и навсегда". Для большого возможного числа применений.

Небольшая легенда:

%S - это Self.
\ - это ;
%P - родительский элемент.
%G - это базовые классы.
%R - это реализуемые интерфейсы.
%T - это тип выражения.
%C - это дочерние элементы.
%CN - имя дочернего элемента. Т.е. на "привычном языке" это - Child.Name.
%CS - имя стереотипа дочернего элемента.
%S%{Facet} - значение поля (member) от Self. Т.е. на "привычном языке" это - Self.Facet.
%f _Name - объявление функции с именем Name текущего стереотипа (метод класса).
f _Name - объявление свободной функции.
%t _constraint - объявление трансформатора с именем constraint текущего стереотипа. Аналог Case.

: ServiceImplementation::Class - объявляет стереотип ServiceImplementation.

= ServicePrim::Class - наследует его от ServicePrim.

? Реализация сервиса - задаёт документацию к текущему элементу.

Цикл:

<{}{%CS=Dependency}%CN>
// - перебирает дочерние элементы, которые являются зависимостями и выводит их имена (%CN)

<{}{%t_simple_class(%P)=true}%PN>
// - перебирает родителей, которые являются "простыми классами" и выводит их имена (%PN)

Оператор 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
// т.е. если Self.Mixin не установлено, то ищем среди детей, того который является PureMixIn

Метод стереотипа:

%f _AfterClassSpell
//#UC START# *5502CBD4031Efor5502BADD01CB*
 %S%[inherited]
//#UC END# *5502CBD4031Efor5502BADD01CB*
// procedure Service.AfterClassSpell; override;
//begin
// inherited;
//end;

Как минимум 10-20 уже написанных классов претерпят изменения в соответствии с этой парадгмой. Уж очень надоели паразитные кросс-зависимости между разными библиотеками.

Ведь почему возникают "паразитные" кросс-зависимости?

Не потому, что люди не знают про инверсию зависимостей (Dependency inversion principle).

А потому, что людям зачастую "лень" писать "всё это хозяйство".

Проще "лишний uses написать".

А подчас люди просто не в курсе, что их изменения могут повлиять на соседние проекты.

И это - нормально.

Зато теперь, когда такие паразитные зависимости выявлены, то они разрешатся буквально "в два клика".

Комментариев нет:

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