Продолжение про инверсию зависимостей.
Исходный пост был тут - Коротко. Ни о чём. Инверсия зависимостей.
Там были две диаграммы:
Диаграмма 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 написать".
А подчас люди просто не в курсе, что их изменения могут повлиять на соседние проекты.
И это - нормально.
Зато теперь, когда такие паразитные зависимости выявлены, то они разрешатся буквально "в два клика".
Комментариев нет:
Отправить комментарий