Продолжение про инверсию зависимостей.
Исходный пост был тут - Коротко. Ни о чём. Инверсия зависимостей.
Там были две диаграммы:
Диаграмма 1:
Диаграмма 2:
Я немного "поколдовал" над шаблонами генерации и диаграммы стали такими:
Диаграмма 1:
- тут мы фактически определяем сервис DispatcherHelper.
Диаграмма 2:
- тут мы определяем одну из реализаций сервиса DispatcherHelper. С именем TvcmDispatcherHelper.
Код остался ТЕМ ЖЕ.
Реализация шаблонов:
Шаблоны "на птичьем языке" выглядят конечно устрашающе. Но зато написаны "раз и навсегда". Для большого возможного числа применений.
Небольшая легенда:
%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.
? Реализация сервиса - задаёт документацию к текущему элементу.
Цикл:
Оператор if:
Метод стереотипа:
Как минимум 10-20 уже написанных классов претерпят изменения в соответствии с этой парадгмой. Уж очень надоели паразитные кросс-зависимости между разными библиотеками.
Ведь почему возникают "паразитные" кросс-зависимости?
Не потому, что люди не знают про инверсию зависимостей (Dependency inversion principle).
А потому, что людям зачастую "лень" писать "всё это хозяйство".
Проще "лишний uses написать".
А подчас люди просто не в курсе, что их изменения могут повлиять на соседние проекты.
И это - нормально.
Зато теперь, когда такие паразитные зависимости выявлены, то они разрешатся буквально "в два клика".
Исходный пост был тут - Коротко. Ни о чём. Инверсия зависимостей.
Там были две диаграммы:
Диаграмма 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 написать".
А подчас люди просто не в курсе, что их изменения могут повлиять на соседние проекты.
И это - нормально.
Зато теперь, когда такие паразитные зависимости выявлены, то они разрешатся буквально "в два клика".




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