Cloud of Science. 2018. T. 5. № 1 http:/ / cloudofscience.ru
Программно-математические средства рефакторинга UML-диаграмм классов с учетом заданных критериев качества
О. А. Дерюгина
Московский технологический университет (МИРЭА) 119454, Москва, пр-т Вернадского, 78
e-mail: [email protected]
Аннотация. Статья посвящена задаче рефакторинга UML-диаграмм классов, на основе которых проектируется платформо-независимая модель объектно-ориентированной архитектуры программного обеспечения в рамках модельно ориентированного подхода, предложенного организацией OMG. В статье сформулирована формальная постановка задачи рефакторинга UML-диаграмм классов, предложены математические методы задания функции структурной семантики UML-диаграммы классов и описания семантически эквивалентных трансформаций. Также предложены алгоритмы трансформации UML-диаграмм классов и рефакторинга, расчета объектно-ориентированных метрик. В работе представлено программное средство UML Refactoring, позволяющее проводить ре-факторинг UML-диаграмм классов, представленных в формате XMI. В заключение разработана методика рефакторинга UML-диаграмм классов при помощи программного средства UML Refactoring. Ключевые слова: проектирование программного обеспечения, архитектура программного обеспечения, MDA, рефакторинг, рефакторинг UML-диаграмм классов.
1. Введение
В условиях большого разнообразия технологических платформ и технологий на рынке IT-услуг становится необходимым разработать такой подход к построению архитектуры программного обеспечения, который позволял бы обеспечить быстрый переход с одной платформы на другую, а также позволял бы производить автоматическую генерацию кода под разные программные платформы.
Для решения данной задачи группой OMG разрабатывается модельно-ориентированный подход MDA [1]:
MDA (Model Driven Architecture — Архитектура под управлением модели) — концепция, предложенная организацией OMG (Object Management Group), заключающаяся в разделении разработки программной системы три основных этапа: PIM (Platform Independent Model — Платформо-независимая модель), PSM (Platform
Specific Model — Платформо-зависимая модель) и Code Model (Программная реализация системы) (рис. 1).
• PIM
- Platform Independent Model.
Описывает бизнес-логику приложения без технических деталей
>PSM
- Platform Specific Model. Описывает модель ПС, реализованной на основе конкретной технологической платформы (например, СУБД)
•Code Model
программная реализация системы
Platform
Independent Model
Platform Specific Model
Code Model
Рисунок 1. Основные этапы разработки ПО в рамках подхода MDA
На уровне создания PIM формулируются функциональность системы и способы взаимодействия с промежуточным слоем программного обеспечения и другими программными системами.
Затем PIM-представление проектируемой системы при помощи автоматических трансформаций отображается в PSM-представлении, описывающее модель программной системы на основе конкретной технологической платформы.
Далее из PSM-представления генерируется код программной реализации системы — Code Model.
Таким образом, для перехода на другую платформу или технологию не требуется заново проектировать логику системы, нужно лишь отобразить уже готовую платформо-независимую модель PIM на PSM-представление для новой платформы.
Для реализации подхода MDA организацией OMG разработаны следующие стандарты: MOF [2], UML [3], XMI [4], OCL [5] и др.
MOF 2 (Meta Object Facilities) — спецификация, разработанная группой OMG для описания метамоделей языков MDA. В основе MOF лежит подмножество языка UML 2.
UML (Unified Modelling Language) — унифицированный графический язык моделирования, позволяющий описывать программные системы, бизнес процессы и т. д. UML можно использовать как для спецификации моделей для последующей разработки системы, так и для реконструкции моделей уже существующих систем.
UML-модель состоит из следующих основных элементов [3]:
- классификаторы (classifiers);
- события (events);
- действия (behaviors).
UML содержит конструкции для моделирования: спецификации экземпляров, спецификации вхождения, спецификации выполнения для моделируемых объектов.
Для моделирования системы при помощи UML используются следующие диаграммы:
- диаграмма деятельности (Activity Diagram);
- диаграмма классов (Class Diagram);
- диаграмма коммуникации (Communication Diagram);
- диаграмма компонентов (Component Diagram);
- диаграмма составной структуры (Composite Structure Diagram);
- диаграмма развертывания (Deployment Diagram);
- диаграмма общего взаимодействия (Interaction Overview Diagram);
- диаграмма объектов (Object Diagram);
- диаграмма пакетов (Package Diagram);
- диаграмма профилей (Profile Diagram);
- диаграмма состояний (State Machine Diagram);
- диаграмма прецедентов (Use Case Diagram).
Стандарт XMI специально разработан для обмена моделями между инструментальными средствами.
Как указывается в документе, XMI предоставляет:
- представление объектов в терминах XML элементов и атрибутов;
- стандартные механизмы связи объектов в одном файле или между несколькими файлами;
- валидацию XMI документов с использованием XML схем;
- идентификацию объектов посредством обращения к ним через ID или UUID.
Синтаксис XMI-документа описан в спецификации при помощи EBNF.
Стандарт OCL описывает декларативный язык для задания спецификаций к MOF-моделям, в том числе и к UML-моделям.
Стандарт QVT описывает три языка трансформаций моделей: QVTr (Relations Language), QVTc (Core Language), QVTo (Operational Mappings Language).
QVTr и QVTc — декларативные языки, позволяют описывать двунаправленные преобразования моделей. QVTo — императивный язык, позволяет описывать однонаправленные преобразования.
Модельно-ориентированный подход MDA позволяет на начальном этапе проектирования платформо-независимой модели PIM абстрагироваться от деталей, связанных с выбором той или иной технологической платформы, и сосредоточиться на бизнес-логике.
Данное обстоятельство позволяет упростить переход с одной платформы на другую, т. к. бизнес-логика приложения не привязана к особенностям реализации конкретной технологической платформы.
Кроме того, модельно-ориентированный подход позволяет вносить изменения в бизнес-логику проекта, а затем при помощи автоматизированных трансформаций заново переносить изменения в Р8М-модель и программную реализацию.
Предложенная концепция МБЛ является полноценной исследовательской программой, связанной с вопросами создания, трансформации, анализа, хранения и передачи моделей программных систем.
Задачей, непосредственно связанной с данной концепцией, является разработка методов, алгоритмов и программных средств автоматизированного рефакторин-га Р1М-модели программного продукта, описанной при помощи языка ИМЬ.
Рефакторинг — реструктуризация системы, сохраняющая ее поведение, направленная на улучшение таких критериев качества, как гибкость, сопровождае-мость, степень повторного использования, сложность, модульность и др.
Одной из ключевых ИМЬ-диаграмм является диаграмма классов, описывающая архитектуру программного продукта как набор классов системы, интерфейсов и связей между ними.
Задача автоматизированного рефакторинга ИМЬ-диаграмм классов является актуальной и важной задачей, т. к. она нужна для создания программных средств поддержки проектирования объектно-ориентированной архитектуры программного обеспечения в рамках подхода МБЛ.
Задача автоматизированного рефакторинга ИМЬ-диаграмм классов заключается в поиске для заданной ИМЬ-диаграммы классов й таких трансформаций ^ е Т, которые снижают/увеличивают значение целевой функции /(й) над подмножеством элементов диаграммы Е' с Е, Е е й (рис. 2).
Целевая функция
иМЬдиа грамма классов 6
Список трансформаций Т*
Множество трансформаций Т
Рисунок 2. Рефакторинг ПМЬ-диаграмм классов: общая схема
Программное средство рефакторинга ИМЬ-диаграмм классов должно решать следующие задачи (рис. 3):
1. Для поддержки совместимости с другими инструментальными средствами, поддерживающими стандарты МБЛ, обеспечивать импорт и экспорт ИМЬ-диаграмм классов в формате ХМ1.
2. Поддерживать расчет основных объектно-ориентированных метрик для анализа метрических параметров ИМЬ-диаграммы классов.
3. Осуществлять поиск трансформаций над подмножеством элементов диаграммы, применение которых снижает/увеличивает значение целевой функции.
4. Обеспечивать автоматизированное применение выбранной пользователем трансформации к ИМЬ-диаграмме классов.
Рисунок 3. Функциональные требования к программному средству рефакторинга ПМЬ-диаграмм классов
Распространенным является подход, при котором в уже написанный и работоспособный код программы вносятся изменения, направленные на повышение читаемости кода, его гибкости, облегчение возможностей сопровождения и т. д.
В данной области написано множество работ, содержащих общие принципы, рекомендации и правила по улучшению качества кода программного обеспечения. Основополагающими в области рефакторинга кода являются работы [6-9], в которых содержатся подробные описания паттернов (шаблонов) проектирования, рецепты рефакторинга, принципы написания хорошо структурированного объектно-ориентированного программного кода.
Одной из сложностей автоматизации процесса рефакторинга является то, что часто предлагаемые авторами решения основаны на субъективных экспертных оценках, которые бывает сложно обосновать математически.
Все же некоторые из методов, предложенных для рефакторинга кода, могут быть использованы и при рефакторинге архитектуры программного обеспечения.
Среди основных подходов к рефакторингу UML-диаграмм классов можно выделить подход, основанный на методах поисковой программной инженерии, использующей методы эвристического поиска решения для решения задач программной инженерии; а также подход, основанный на применении детерминированных алгоритмов анализа и рефакторинга в процессе взаимодействия с пользователем (табл. 1).
Таблица 1. Основные подходы к рефакторингу UML-диаграмм классов
№ Подход Описание подхода Достоинства Недостатки
1 Рефакторинг , основанный на методах SBSE (Search Based Software Engineering) На вход подается целевая функция, диаграмма классов, набор трансформаций, погрешность. Эвристический алгоритм производит поиск диаграммы, для которой значение целевой функции минимально/максимально возможное 1. Алгоритм находит по крайней мере локальный минимум для целевой функции. 2. Большое количество подробно изученных эвристических алгоритмов: генетические алгоритмы, симуляция отжига, алгоритмы роевого интеллекта и др. Алгоритм может применить трансформации так, что в результате получится бессмыслица
2 Автоматизированный рефакторинг На вход подается целевая функция, диаграмма классов, набор трансформаций. Алгоритм предлагает пользователю список трансформаций, которые снижают/увеличивают значение целевой функции Окончательное решение принимает проектировщик, обладающий большими сведениями о разрабатываемой системе, чем те, которые содержатся в диаграмме классов Следуя рекомендациям системы, проектировщик может не получить диаграмму, для которой значение целевой функции минимально возможное
Для решения задачи рефакторинга UML-диаграмм классов нужно решить следующие подзадачи:
1) разработать формальный аппарат доказательства семантической эквивалентности трансформаций UML-диаграмм классов;
2) сформулировать критерий рефакторинга — целевую функцию;
3) оценить влияние трансформаций на целевую функцию;
4) разработать алгоритм поиска элементов диаграммы трансформаций, снижающих значение целевой функции;
5) для каждой трансформации разработать алгоритм ее автоматизированного применения к диаграмме.
На сегодняшний день разработаны программные средства рефакторинга UML-диаграмм классов: Darwin [10], Dearthóir [11], CODe-Imp [12], Bunch tool [13] и др.
Система Darwin реализована в виде плагина для IDE Eclipse. Основана на подходе SBSE с применением генетического алгоритма. Интегрируется с CASE-
средством UML2Tools из экосистемы Eclipse. В начале пользователь строит UML-диаграмму прецедентов (Use-case Diagram), затем на ее основе распределяет классы по пакетам, где классы каждого пакета отвечают за одну обязанность (responcibility), в результате чего формируется граф распределения обязанностей (RDG — Responcibilities Dependency Graph).
На основе полученного от пользователя RDG система Darwin автоматически строит null-диаграмму классов проектируемой системы, которая подается на вход генетическому алгоритму. Также пользователю требуется задать число индивидов в популяции, число поколений эволюции.
Хромосома представляет собой список паттернов проектирования, которые были применены к классам диаграммы. В качестве мутации используется применение/удаление в диаграмме паттернов проектирования (Adapter, Interface, Strategy, Template Method) к произвольному классу системы. Операция скрещивания — взять часть паттернов от одного родителя, а другую часть — от второго. Недостатком подхода является произвольное, зачастую лишенное смысла применение трансформаций к элементам диаграммы классов. Кроме того, авторы используют в том числе и паттерны, применение которых на этапе проектирования вызывает сомнения (например, применение паттерна Адаптер).
Система Dearthóir также основана на подходе SBSE, основана на алгоритме симуляции отжига. Инструментальное средство проводит реструктуризацию иерархии классов, перемещает методы между классами для минимизации дублирования кода.
Система CODe-Imp, разработанная авторами Dearthóir, основана также на подходе SBSE, предоставляет пользователю выбрать один из алгоритмов поиска и подмножество рефакторингов.
Система Bunch tool позволяет проводить автоматическое разбиение на модули. Основана на алгоритмах кластеризации, генетическом алгоритме и алгоритме наилучшего спуска.
В качестве целевой функции в данных системах используются взвешенные суммы нескольких метрик объектно-ориентированного программирования (таких как CBO, LCOM и др.).
2. Математические методы рефакторинга UML-диаграмм классов
Определение. UML-диаграммой классов d называется такая UML-диаграмма, что d = {C, I, R}, где C — множество классов C = {с,..., ck}, I — множество интерфейсов I = ,..., i}, R — множество отношений R = {rx,..., rg}.
Определение. Классом c называется такой элемент диаграммы классов d, что c = {A, M, F}, где A — множество атрибутов A = {aj,..., a}; M — множество методов M = {m,..., m}; F — множество дополнительных параметров класса, таких как статичность, идентификатор доступа и т. д.
Определение. Атрибутом a называется такой элемент класса c, что a = {F}, где F — множество свойств атрибута, таких как видимость атрибута v = {public, protected, private}, тип атрибута t, признак виртуальности атрибута v' и др.
Определение. Методом m называется такой элемент класса или интерфейса, что m = {P, F}, где P — множество входных параметров метода P = {p,..., pn}, pt = {tp , np }, где tp — тип параметра ; np — имя параметра p1 ; F — множество свойств метода, таких как видимость метода v = {public, protected, private}, тип возвращаемого значения t, признак виртуальности метода v признак статичности метода s, имя метода n и др.
Определение. Интерфейсом i называется такой элемент UML-диаграммы классов, что i = {M}, где M — множество методов M = {mx,..., m}.
Определение. Отношением r называется такая связь между элементами UML-диаграммы, что r = {n, t, e, e2, p}, где n — имя отношения; t — тип отношения, e — идентификатор начального участника отношения; e2 — идентификатор конечного участника отношения; p — мощность отношения.
В диаграмме классов отношения между ее элементами подобны дугам в графе.
Между классами некоторой диаграммы классов d возможны следующие виды отношений (relations):
1) ассоциация (association);
2) наследование — обобщение (generalization);
3) агрегация (aggregation);
4) композиция (composition);
5) зависимость (dependency);
Между классом и интерфейсом возможно отношение реализации (realization).
assoc
Определение. Выражение ^ ^ c2i означает, что класс c связан отношением ассоциации мощностью (p, p2 ) с классом c2, где p, p2 — количество объектов классов c и c2 соответственно, участвующих в отношении (табл. 2).
Таблица 2. Запись мощности отношения между элементами диаграммы классов
Мощность отношения (Р^ Р2)
один к одному (1, 1)
один ко многим (1, 1 ... n) или (1, 0 ... n)
многие ко многим (1 ... n, 1 ... n) или (0 ... n, 0 ... n), или (1 ... n, 0 ... n), или (0 ... n, 1 ... n)
многие к одному (1 ... n, 1) или (0... n, 1)
Например, запись с 1 ^ о...п с2 означает, что каждый объект класса с связан отношением ассоциации с 0...п объектов класса с2 •
В случае, если мощность отношения указывать не требуется, запись выглядит
следующим образом: с1 ^ с2.
gener
Определение. Выражение сх ^ с2 означает, что класс с наследует методы и атрибуты класса с .
Определение. Выражение c ^ c2 означает, что класс ег связан с классом c2 отношением агрегации.
comp
Определение. Выражение c ^ c2 означает, что класс c связан с классом c2 отношением композиции.
dep
Определение. Выражение c ^ С означает, что класс c связан с классом c2 отношением зависимости.
Семантическая функция S (d) сопоставляет диаграмме классов d значение ее структурной семантики: множество классов, интерфейсов отношений между ними.
Предположим, что заданными являются следующие семантические области:
1. Множество классов C = {c } UML-диаграммы d, каждый из которых содержит набор атрибутов и методов c = {A, Ml}.
2. Множество интерфейсов I = {i.} UML-диаграммы d, каждый из которых содержит набор методов il = {M1}.
3. Множество отношений R = {rt} UML-диаграммы d.
Структурную семантику UML-диаграммы классов d зададим функцией [14]: S(d) = {{C}, {I}, {R}}.
Рисунок 4. Диаграмма классов d
Например, значение структурной семантики диаграммы классов d, изображенной на рис. 4, будет следующим :
S\d) = {{q = {{а;,..., ¿а H1}}, с2 = {{a2,..., a52}, im2, тЩ,
Сз = {Ц3, ¿2, ¿33}, {mf, ml, m3,}}, с4 = {{af}, {0}}, с5 = {{0}, {0}}},
gener gener aggreg aggreg
{0}, {r = С3 ^ С;, r = С4 ^ С;, Гз = С1 ^ С2, rf = С2 ^ С5}}. Трансформацией t некоторой UML-диаграммы классов d будем называть функцию отображения:
t (d, Е): d ^ d ',
где Е — подмножество элементов е е d ; d ' — диаграмма классов, полученная в результате применения к диаграмме классов d трансформации t над ее подмножеством элементов.
Будем считать, что семантически эквивалентная трансформация UML-диаграммы d — это такая функция отображения t (d, Е): d ^ d ', что:
S *(d ) = S *(d ' ),
Замечание. То есть под семантически эквивалентной трансформацией UML-диаграммы будем понимать такое изменение структурных элементов UML-диаграммы d, которое обеспечивает инвариантность ее семантического значения 5 *(d ).
Трансформация «Введение интерфейса» подразумевает создание промежуточного звена между классами, реализующими некоторое множество методов М, и классами, которые обращаются к данному множеству через отношения r типа dependency (зависимость).
Аксиома 1 (Вторая эквивалентная трансформация) — Интерфейс
dep real
s *(d) = {{с, = (4, м,}, с2 = а м 2}}, {i = м;'}, (с2 ^ i, с, ^ i}} =
dep
= {{с, = {А,,М;}, с2 = {42,М2}}, {0}}, {с2 ^с,}.
Фасад — паттерн, структурирующий объекты. Предоставляет унифицированный интерфейс вместо набора интерфейсов некоторой подсистемы. Фасад определяет интерфейс более высокого уровня, который упрощает использование подсистемы (рис. 5 и 6).
Рисунок 5. Диаграмма классов до применения паттерна «Фасад» Аксиома 2 (Третья эквивалентная трансформация) — Фасад (Façade)
S\d) = {{cl={4,Ml},c2={4,M2}}, c„={4,M„}},{...},{{ck,c2\\c3\\...\\c„}5 {ст, c2\\c3\\...\\cJJ} = {{c1={AU{c2,...cJ1,M1UM1U...UMJ,c2={A2,M2},---,
deep
deep
Сп = {А,Мп}}> {-}}> К ^с, •••> ^с}
где с — класс-обертка («фасад») для остальных классов с2,..., си; А — множество атрибутов класса с; М — множество методов класса с.
Class2
+Operation2_l() +Operation2_2() +Operation2_3()
Class3
+Operation3_l() +Operation3_2() +Operation3_3()
Class4
+Operation4_l() +Operation4_2()
Facade
-class2 -class3 -class4
+Operation2_l() +Operation2_2() +Operation2_3() +Operation3 1() +Operatio3_2nlO +Operation3_3() +Operation4_l() +Operation4_2()
Class7
Class5
' Class6
Рисунок 6. Диаграмма классов после применения паттерна «Фасад»
Паттерн «Стратегия» определяет семейство алгоритмов, инкапсулирует каждый из них и обеспечивает их взаимозаменяемость (рис. 7 и 8).
С las si
+Operationl_l() +Operationl_2() +Operationl_K() +OperationP_l() +OperationP_2() +OperationP_L()
ClassO
+Attributel ♦AttributeF
+Operationl() +OperationW()
Class2
+Operationl_l() +Operationl_2() +Operationl_K() +OperationP_l() +OperationP_2() +OperationP_L()
.-V
«interface» Interfacel
+Operationl_l() +Operationl_2() +Operationl_K()
<3 A
ClassN
+Operationl_l() +Operationl_2() +Operationl_K() +OperationP_10 +OperationP_2() +OperationP_LQ
«interface» InterfaceP
... -+OperationP_2() +OperationP_L0
<1^
Рисунок 7. Предпосылки к применению паттерна «Стратегия»
Рисунок 8. Результат приведения к паттерну «Стратегия»
Аксиома 3 (Аксиома о субклассировании поведения) S\d) = {{cx = {Al,Ml), с2 ={А2,М2 UM/}}, {/j =М/}}}, {{с2, сх}2, {с2, i,}6}} =
gener aggreg
= {{Cl ={Д щ, Mx UM;}, c2 = {A2,M2}}, {/• ={M;}}}, C2 -> ?1 -> cj}.
Теорема. Семантическая эквивалентность применения паттерна Стратегия
S\d) = {{Cl = {4,Mt}, с2 = {А,м2 им;и...им;},..., с„ = {Ап,м„ U...им;»,
gener gener real real
ih ={M[},..., ip ={M'p}}}, {c2 ->cl5 ..., c„ ->cl5 c2^iu...,ip, ...,cn^iu...,ip}} =
= {{Cl ={AX U/; U... \лр,м, им;и...им;}, c2 = {a2,m2},..., c„ = {An,MJ},
gener gener aggreg aggreg
ih = М} } } , с2 — с, • • • , с2 — с, h — с, . . . , ip — с} } • Доказательство.
Пусть задана диаграмма классов d, значение структурной семантики которой равняется:
^(£/) = {{с1={д,м1},с2={А2,м2им;и...им;},..„ с„ ={д,,м„и...им;}},
gener gener real real
ft = {м[},..., 1р = м}}}, {с2 — с,..., сп — с, с2— i,...,ip,...,сп— i,...,ip}}.
Поочередно убирая по (А3) для каждого класса с, i е 2,..., п отношение реали-
real
зации интерфейса i., j е 1,..., р, с ^ij, добавляя классу с атрибут ij и методы
aggreg
М', а также добавляя диаграмме отношение агрегации i ^ с, получаем:
S\d) = {{cl={AlUilU...Uip,MlUM;U...UM'p},c2={A2,M2}, ....,cn={An,MJ},
gener gener aggreg aggreg
(ii = (М[ }}}, (c2 ^ ex, ..., сп ^ с1г i ^ с15..., ip ^ Cl}>.
Что и требовалось доказать.
На основе разработанных математических средств описания семантики UML-диаграмм классов и их трансформации мы теперь можем сформулировать задачу автоматизированного рефакторинга UML-диаграмм классов следующим образом.
Пусть дана UML-диаграмма классов d, множество семантически эквивалентных трансформаций Т, целевая функция f (d).
Требуется найти такое множество пар (t, Е}, таких, что: d' = t(d, е), Af (d') < 0. Путь дана диаграмма классов d = (С, I, R, Р}.
Тогда функция К(d) определяет сложность диаграммы классов d следующим образом:
к (d) =| с |+111+1 R | +х;=о1 д1 +z;=oi м | =oi М; , i (i>
где К(d) — сложность UML-диаграммы классов d; С — множество классов диаграммы d; I — множество интерфейсов диаграммы d; R — множество отношений диаграммы d; Д — множество атрибутов класса с , с е С, i е 0,..., п; М — множество методов класса с, С е С, i е 0,..., п, за исключением методов, принадлежащих реализуемым классом с интерфейсам i, l е 0,..., к, где к — число реализуемых классом с интерфейсов; М; — множество методов интерфейса ij, ij е I, j е 0,..., т.
Для внутреннего представления UML-диаграммы классов в инструментальном средстве требуется разработка специальной абстрактной структуры данных (АСД), позволяющей осуществлять расчет объектно-ориентированных метрик, а также преобразование диаграммы классов.
UML-модель программной системы в целом может быть представлена в оперативной памяти компьютера при помощи абстрактной структуры UML Map (рис. 9).
АСД UML Map содержит хеш-таблицы объектов, соответствующих диаграммам классов, прецедентов, последовательностей, состояний и т. д. Каждый объект содержит в себе информацию о соответствующей ему диаграмме в формате XMI. К примеру, для диаграммы классов объект хранит информацию о классах, их названиях, методах, свойствах, о связях между классами, об интерфейсах, методах, которые они реализуют.
Рисунок 9. Диаграмма классов, описывающая абстрактную структуру данных UML Map
API (Application Programming Interface) структуры данных UMLMap приведен в табл. 3.
Таблица 3. API абстрактной структуры данных UMLMap
Класс UMLMap void addClassDiagram(ClassDiagram diagram) void addSequenceDiagram(SequenceDiagram diagram) void addActivityDiagram(ActivityDiagram diagram) void addStateChartDiagram(StateChartDiagramdiagram) void addUseCaseDiagram(UseCaseDiagram diagram) void addComponentDiagram(ComponentDiagram diagram) void deleteClassDiagram(String id) void deleteSequenceDiagram(String id) void deleteActivityDiagram(String id) void deleteStateChartDiagram(String id) void deleteUseCaseDiagram(String id) void deleteComponentDiagram(String id) ClassDiagram getClassDiagram(String id) SequenceDiagram getSequenceDiagram(String id) ActivityDiagram getActivityDiagram(String id) StateChartDiagram getStateChartDiagram(String id) UseCaseDiagram getUseCaseDiagram(String id) ComponentDiagram getComponentDiagram(String id)
На рис. 10 показана подробная UML-диаграмма классов для ClassDiagram.java.
Рисунок 10. Диаграмма классов для абстрактной структуры данных UML Map: ClassDiagram
3. Алгоритмы рефакторинга UML-диаграмм классов
3.1. Алгоритмы применения трансформаций к UML-диаграммам классов
Пусть даны диаграмма d, класс с. Тогда алгоритм трансформации «Введение интерфейса» для АСД UMLMap выглядит следующим образом (листинг1):
Листинг 1. Трансформация «Введение интерфейса» i = d.interfaceAdd(c.getPublicOperations()) for each r e relations
if (r.getType() == dependency)
if (r.getEndId() == c.getIdQ) r.setEndId(i.getId()) d.relationAdd(c.getId(), i.getId(), "realization")
Пусть даны диаграмма d, классы classes, методы methods. Тогда алгоритм трансформации «Введение интерфейса» для нескольких классов для АСД UMLMap выглядит следующим образом (листинг 2):
Листинг 2. Трансформация «Введение интерфейса» для нескольких классов
i = new Interface()
i.operationsAdd(methods)
d.interfaceAdd(i)
for each r e relations
if (r.getType() == dependency) if (r.getEndId() == c.getIdQ) r.setEndId(i.getIdQ) for each c e classes
d.relationAdd(c.getId(),i.getId(), "relalization")
Пусть даны диаграмма d, класс-родитель parent, список дочерних классов childClasses, список интерфейсов interfaces. Тогда алгоритм трансформации «Стратегия» для АСД UMLMap выглядит следующим образом (листинг 3):
Листинг 3. Трансформация «Стратегия» for each i e interfaces parent.attributeAdd(i) parent.operationAdd(i.getOperations()) for each c e childClasses
c. delete(i.getOperations())
d.addRelation(i.getId(),parent.getId()/'composition")
d. relationDelete(parent.getIdQ,inter.getId(), "realization"); for each c e childClasses
d.relationDelete(c.getId(),inter.getIdQ,"realization"); for each r e d
if (r.type == "dependency") if (r in interfaces) r.setEndId(parentId);
Пусть даны диаграмма d, класс-фасад facade, список внутренних классов in-nerClasses. Тогда алгоритм трансформации «Фасад» для АСД UMLMap выглядит следующим образом (листинг 4):
Листинг 4. Трансформация «Фасад» for each c e innerClasses façade.attributeAdd(c)
façade.operationAdd(c.getPublicOperations()) for each r e d
if (r.getType == "dependency") if (r.getEndId == c.getId()) r.setEndId(façade.getId())
d. relationAdd(facade.getId(),c.getId(),"composition")
Алгоритм CDTA (Class Diagram Transformation Analysis) будет выглядеть следующим образом (листинг 5):
Листинг 5. Алгоритм CDTA for each teT
L = search(t,d,f) //поиск пар {t,E}, при которых Af(d') < 0 Q.add(L) //добавление пар {t,E} к результирующему списку return Q
Функция search(t,d,f) работает следующим образом (листинг 6): Листинг 6. Функция search(t,d,f) L1 = analyze(t,d) //поиск множеств элементов E диаграммы d для //трансформации
for each eeL1
d' = refactor(e,t,d) //применение трансформации t к диаграмме d if (f(d') < f(d)) //проверка на уменьшение значения целевой функции L2.add(t,e) //добавление к результату return L2
3.2. Алгоритм рефакторинга UML-диаграмм классов CDTA
Алгоритм CDTA (Class Diagram Transformation Analysis) будет выглядеть следующим образом (листинг 7):
Листинг 7. Алгоритм CDTA for each teT
L = search(t,d,f) //поиск пар {t,E}, при которых Af(d') < 0 Q.add(L) //добавление пар {t,E} к результирующему списку return Q
Функция search(t,d,f) работает следующим образом (листинг 8): Листинг 8. Функция search(t,d,f) L1 = analyze(t,d) //поиск множеств элементов E диаграммы d для //трансформации
for each eeL1
d' = refactor(e,t,d) //применение трансформации t к диаграмме d if (f(d') < f(d)) //проверка на уменьшение значения целевой функции L2.add(t,e) //добавление к результату return L2
3.3. Алгоритмы поиска множеств элементов E диаграммы классов для применения трансформаций
Алгоритм поиска множеств элементов диаграммы Е, к которым может быть применена трансформация «Введение интерфейса», может быть описан следующим образом:
1. Найти все классы с е d, которые не реализуют ни одного интерфейса, и добавить их к списку l .
2. Среди классов из списка l найти те с, которые участвуют в отношениях dependency вида: сj ^ с, и добавить их в список l2.
3. Для каждого класса с,- вычислить Af (d).
4. Вернуть все сi, для которых Af (d) < 0.
Для абстрактной структуры данных UML Map алгоритм может быть описан следующим образом (листинг 9):
Листинг 9. Алгоритм поиска списка классов для применения трансформации «Введение интерфейса»
1.for each c in classes
2. fl = false
3. for each r in relations
4. if (r.getStartId() == c.getId())
5. if (r.getType()=="realization")
6. fl = true
7. if (!fl)
8. ll.add(c)
9.for each c in ll
10. fl = false
11. for each r in relations
12. if (r.getEndId() == c.getId())
13. if (r.getType()=="dependency")
14. fl = true
15. if (fl)
16. l2.add(c)
17.for each c in l2
18. if (Af(c,d)<0)
19. l3.add(c)
20.return l3
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 11. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Для диаграммы d, представленной в форме АСД UML Map, получаем следующий псевдокод (листинг 10):
Листинг 10. Реализация алгоритма поиска списка классов для применения трансформации «Введение интерфейса» для АСД UML Map
1. for each relation in relations
2. if (relation.getType() == "realization")
3. l1.add(relation.getStartID())
4. for each class in classes
5. if (!l1.has(class.getId()))
6. l2.add(class.getId())
7. for each relation in relations
8. if (relation.getType() == "dependency)"
9. if (l2.has(relation.getEndID())
10. l3.add()
11. return l3
Performance of the Interface transformation analysis algorithm
_ 0,00250000000000000000
1 0,00200000000000000000 о '
Js 0,00150000000000000000
J 0,00100000000000000000
on i0,00050000000000000000
Üä 0,00000000000000000000 ж
0 50 100 150 200 250 300 350 UML class diagram size (number of classes)
Рисунок 11. Зависимость времени работы алгоритма анализа для трансформации «Введение интерфейса» от размера UML-диаграммы классов
Алгоритм поиска множеств элементов Е диаграммы d, к которым может быть применена трансформация «Стратегия», описывается следующим образом:
1. Для каждого класса диаграммы d найти те, у которых есть потомки, и добавить их в хеш-таблицу <Class, List<Class>> / = {{с ,{сп, ся,...}},...}.
2. Для каждого класса из / проверить, реализуют ли его потомки какие-либо интерфейсы. Если да — добавить их в хеш-таблицу <Class,List<Class>> 12 = {{с,,{сп, сп,...}},...}.
3. Для каждого класса из /2 рассчитать Af (d). Если Af (d) < 0 — добавить в список /3 = {parentid, {childclassesids}, {interfacesids}}.
4. Вернуть /3.
Для абстрактной структуры данных UML Map алгоритм может быть описан следующим образом (листинг 11):
Листинг 11. Реализация алгоритма поиска списка классов для применения трансформации «Стратегия» для АСД UML Map
1.for each c in classes
2. inheritors = null
3. for each r in relations
4. if (r.getEndId() == c.getId())
5. if (r.getType() == "generalization")
6. inheritors.add(r.getSta rtId())
7. l1.add(c.getId,inheritors)
8.for each c in 11
9. interfaces = null
10. for each r in relations
11. if (r.getStartId() == c.getId())
12. if (r.getType() == "realization")
13. interfaces.add(r.getEndId())
14. l2.add(c.getId, interfaces)
15.for each c in l2
16. inheritors = l1.get(c.getId())
17. interfaces = l2.get(c.getId())
18. if (Af(c,interfaces,inheritors,d)<0)
19. l3.add(c,inheritors,interfaces)
20.return l3
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 12. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Strategy transformation analysis algorithm
_ 0,12000000000000000000 -,-,-,-,-,-
I 0,10000000000000000000
0
8 0,08000000000000000000
1 0,06000000000000000000 ? 0,04000000000000000000 uiot0,02000000000000000000 cex0,00000000000000000000
0 50 100 150 200 250 300 350 UML class diagram size (number of classes)
Рисунок 12. Зависимость времени работы алгоритма анализа для трансформации «Стратегия» от размера UML-диаграммы классов
Алгоритм поиска групп классов для применения трансформации «Фасад» для АСД UML Map может быть описан следующим образом (листинг 12):
Листинг 12. Реализация алгоритма поиска списка классов для применения трансформации «Фасад» для АСД UML Map
1.//создать список классов, у которых есть входящие связи типа dependency
2.for each r in relations
3. if(r.getType()=="dependency")
4. if (!!1.containsKey(r.getEndID())
5. l1.put(r.getEndID(), new ArrayList<String>());
6. l1.get(r.getEndID()).add(r.getSta rtId());
7. else
8. l1.get(r.getEndID()).add(r.getSta rtId())
9.//создать список классов, у которых есть общие входящие связи
10.for each key in l1.keySet()
11. l2.put(key, new ArrayList<String>());
12. List<String> classesIdsList = l1.get(key);
13. for each key2 in l1.keySet()
14. if (key2!=key) {
15. //сравнить списки классов и найти общие
16. List<String >tempClassesIdsList = l1.get(key2);
17. if (haveSameIds(classesIdsList,tempClassesIdsList))
18. for each key2 in l1.keySet())
19. if (key2!=key)
20. //сравнить списки классов и найти общие
21. List<String >tempClassesIdsList = l1.get(key2)
22. if (haveSameIds(classesIdsList,tempClassesIdsList))
23. l2.get(classId).add(key2)
24.//сформировать группы классов
25.for each key in l2.keySet()
26. List<String> listTemp = new ArrayList<String>()
27. listTemp.add(key)
28. listTemp.addAll(l2.get(key))
29. l3.add(listTemp)
30.//рассчитать значение целевой функции для каждой группы классов
31.List<Double> fitnessValues = new ArrayList<Double>()
32. for (int i = 0; i < l3.size(); i++)
33. List<String> listTemp = l3.get(i)
34. deltaFitnessValue = getDeltaFitness(listTemp,diagram, fitnessFunction);
35. if (deltaFitnessValue<0)
36. l4.add(listTemp);
37. fitnessValues.add(deltaFitnessValue)
38.//вернуть группы классов, применение к которым паттерна Фасад снижает значение целевой функции
39.for (int i=0; i< l4.size(); i++)
40. String command = createCommand(l4.get(i))
41. double deltaFitnessValue = fitnessValues.get(i)
42. commands.add(new RefactoringCommand("Facade transformation", command))
43. String innerClassesNames = getInnerClassesNames(l4.get(i),diagram)
44. refactorings.add(new FacadeRefactoring(new RefactoringCommand( "Facade
transformation", command), innerClassesNames, deltaFitnessValue)) 45.return refactorings
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 13. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Facade transformation analysis algorithm
_ 0,00014000000000000000
I 0,00012000000000000000
ceo0,00010000000000000000
H 0,00008000000000000000
EE
~ 0,00006000000000000000 с '
ito0,00004000000000000000
о '
Й 0,00002000000000000000 Ш 0,00000000000000000000
0
Рисунок 13. Зависимость времени работы алгоритма анализа для трансформации «Фасад»
от размера UML-диаграммы классов
3.4. Алгоритмы расчета метрик на основе абстрактной структуры данных UML Map
Метрика AverageCBO может быть рассчитана следующим образом (листинг 13).
Листинг 13. Расчет метрики Average CBO
1.public double calculate(ClassDiagram classDiagram) {
2. double result = getAverageCBO(classDiagram);
3. this.value = new SimpleDoubleProperty(result);
4. return result; 5-}
6.public double getAverageCBO( ClassDiagram classDiagram) {
7. int classCount = classDiagram.getClasses().size();
8. double sumCBO = 0;
9. for (Entry<String,Class> entry : 10.classDiagram.getClasses().entrySet()) {
11. sumCBO += getClassCBO(entry.getKey(),classDiagram);
12. }
13. return roundUp(sumCBO/classCount,3);
14.}
15.//Coupling Between Objects for a class
16.public Integer getClassCBO(String classID, ClassDiagram classDiagram) {
17. Integer classCBO=0;
18. for (Entry<String, Relation> entry : 19.(classDiagram.getRelations()).entrySet()) {
20. Relation relation = entry.getValue();
21. if (!relation.getType().equals("generalization")) {
22. if (relation.getEndId().equals(classID) || rela-tion.getStartId().equals(classID) ) {
23. classCBO++;
24. }
50 100 150 200 250 300 350 UML class diagram size (number of classes)
25. }
26. }
27. return classCBO;
28.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 14. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average CBO Metric Calculation Algorithm
350
Рисунок 14. Зависимость времени работы алгоритма расчета метрики Average CBO от размера UML-диаграммы классов
Метрика AverageDIT может быть рассчитана следующим образом (листинг 14).
Листинг 14. Расчет метрики Average DIT
1.public double getAverageDIT( ClassDiagram classDiagram ) {
2. int classCount = classDiagram.getClasses().size();
3. double sumDIT = 0;
4. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
5. sumDIT += getClassDIT(entry.getKey(),classDiagram);
6. }
7. return roundUp(sumDIT/classCount,3);
8.}
9.//Depth of Inheritance Tree
10.public Integer getClassDIT (String classID, ClassDiagram classDiagram ){
11. int classDIT = 0;
12. List<String> classParentIds = new ArrayList<String>();
13. for (Entry<String, Relation> entry : (classDi-agram.getRelations()).entrySet()) {
14. Relation relation = entry.getValue();
15. if (relation.getType().equals("generalization")) {
_ 0,00300000000000000000
1 0,00250000000000000000 o
esc 0,00200000000000000000
J 0,00150000000000000000
ont 0,00100000000000000000
icut0,00050000000000000000 e
w 0,00000000000000000000
50 100 150 200 250 300 UML class diagram size (number of classes)
0
16. if (relation.getStartId().equals(classID)) {
17. classParentlds.add(relation.getEndId());
18. }
19. }
20. }
21. for (int i=0; i<classParentIds.size();i++) {
22. int classDITTemp = getClassDIT(classParentIds.get(i),classDiagram);
23. if (classDIT < classDITTemp+1) {
24. classDIT = classDITTemp+1;
25. }
26. }
27. return classDIT;
28.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 15. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average DIT Metric
Calculation Algorithm
0,00800000000000000000 % 0,00700000000000000000 ocn0,00600000000000000000 s e(0,00500000000000000000 mei0,00400000000000000000 t n0,00300000000000000000 tiu0,00200000000000000000
u
x 0,00100000000000000000 0,00000000000000000000
0 50 100 150 200 250 300 350 UML class diagram size (number of classes)
Рисунок 15. Зависимость времени работы алгоритма расчета метрики AverageDIT от размера UML-диаграммы классов
Метрика Average NOC может быть рассчитана следующим образом (листинг 15):
Листинг 15. Расчет метрики Average NOC
1.public double getAverageNOC(ClassDiagram classDiagram) {
2. int classCount = classDiagram.getClasses().size();
3. double sumNOC = 0;
4. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
5. sumNOC += getClassNOC(entry.getKey(),classDiagram);
6- }
7. double averageNOC = roundUp(sumNOC/classCount,3);
8. return averageNOC; 9-}
10.//Number of Children - number of immediate classes
11.public Integer getClassNOC (String classId,ClassDiagram classDiagram){
12. int classNOC = 0;
13. for (Entry<String, Relation> entry : (classDi-agram.getRelations().entrySet())) {
14. Relation relationTemp = entry.getValue();
15. if (relationTemp.getType().equals("generalization")) {
16. if (relationTemp.getEndId().equals(classId)) {
17. classNOC++;
18. }
19. }
20. }
21. return classNOC;
22.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 16. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average NOC Metric Calculation Algorithm
_ 0,00300000000000000000 —
1 0,00250000000000000000
0
S 0,00200000000000000000
(Л
1 0,00150000000000000000 ~ 0,00100000000000000000 tio0,00050000000000000000
3
gi 0,00000000000000000000
ш 0 50 100 150 200 250 300 350
UML class diagram size (number of classes)
Рисунок 16. Зависимость времени работы алгоритма расчета метрики Average NOC от размера UML-диаграммы классов
Метрика Average DAC может быть рассчитана следующим образом (листинг 16):
Листинг 16. Расчет метрики Average DAC
1.public double getAverageDAC(ClassDiagram classDiagram) {
2. double averageDAC = 0;
3. int sumDAC = 0;
4. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
5. Class classTemp = entry.getValue();
6. sumDAC += getDAC(classTemp,classDiagram); 7- }
8. int classCount = classDiagram.getClasses().size();
9. averageDAC = roundUp(sumDAC/classCount,3);
10. return averageDAC;
11.}
12.public int getDAC(Class classTemp, ClassDiagram classDiagram) {
13. int DAC = 0;
14. for (Entry<String,Attribute> entry: classTemp.getAttributes().entrySet()) {
15. Attribute attributeTemp = entry.getValue();
16. if ( searchClassByName(attributeTemp.getType(), classDiagram)) {
17. DAC++;
18. }
19. }
20. return DAC;
21.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 17. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average DAC Metric Calculation Algorithm
_ 0,00250000000000000000 "XT'
с 0,00200000000000000000 о
и
jX 0,00150000000000000000 ai
.Si 0,00100000000000000000
oin0,00050000000000000000
3
ce0,00000000000000000000
50 100 150 200 250 300 UML class diagram size (number of classes)
350
0
Рисунок 17. Зависимость времени работы алгоритма расчета метрики Average NOC от размера UML-диаграммы классов
Метрика Average NLM может быть рассчитана следующим образом (листинг 17):
Листинг 17. Расчет метрики Average NLM
1.public double getAverageNLM(ClassDiagram classDiagram) {
2. int classCount = classDiagram.getClasses().size();
3. double sumNLM = 0;
4. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
5. sumNLM += getNLM(entry.getKey(),classDiagram);
6. }
7. double averageNLM = roundUp(sumNLM/classCount,3);
8. return averageNLM; 9-}
10.public int getNLM(String classId, ClassDiagram classDiagram) {
11. int NLM = 0;
12. Class classTemp = classDiagram.getClass(classId);
13. for (Entry<String,Operation> entry : classTemp.getOperationsQ.entrySetQ) {
14. Operation operationTemp = entry.getValue();
15. if (!operationTemp.getVisibilty().equals("public")) {
16. NLM++;
17. }
18. }
19. return NLM;
20.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 18. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average NLM Metric Calculation Algorithm
) 0,00003000000000000000 s)
dn0,00002500000000000000 o
cse0,00002000000000000000
E 0,00001500000000000000
no0,00001000000000000000
3 0,00000500000000000000 e
ш 0,00000000000000000000
0
Рисунок 18. Зависимость времени работы алгоритма расчета метрики Average NLM от размера UML-диаграммы классов
Метрика Average NOM может быть рассчитана следующим образом (листинг 18):
50 100 150 200 250 300 350 UML class diagram size (number of classes)
Листинг 18. Расчет метрики Average NOM
1.public double getAverageNOM(ClassDiagram classDiagram) {
2. int classCount = classDiagram.getClasses().size();
3. double sumNOM = 0;
4. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
5. Class classTemp = entry.getValue();
6. sumNOM += getNOM(classTemp); 7- }
8. double averageNOM = roundUp(sumNOM/classCount,3);
9. return averageNOM;
10.}
11.public int getNOM(Class classTemp) {
12. return classTemp.getOperations().size();
13.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 19. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average NOM Metric Calculation Algorithm
0,00001600000000000000 0,00001400000000000000 0,00001200000000000000 0,00001000000000000000 0,00000800000000000000 0,00000600000000000000 0,00000400000000000000 0,00000200000000000000 0,00000000000000000000
50 100 150 200 250 300
UML class diagram size (number of classes)
350
0
Рисунок 19. Зависимость времени работы алгоритма расчета метрики Average NOM от размера UML-диаграммы классов
Метрика DAC2 может быть рассчитана следующим образом (листинг 1 9): Листинг 19. Расчет метрики DAC2
1.public int getDAC2(ClassDiagram classDiagram) {
2. int DAC2 = 0;
3. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
4. Class classTemp = entry.getValue();
5. if (getDAC2(classTemp,classDiagram)) {
6. DAC2++;
7. }
8. }
9. return DAC2;
10.}
11.public boolean getDAC2(Class classTemp, ClassDiagram classDiagram) {
12. for (Entry<String,Attribute> entry: classTemp.getAttributes().entrySet()) {
13. Attribute attributeTemp = entry.getValue();
14. if ( searchClassByName(attributeTemp.getType(), classDiagram)) {
15. return true;
16. }
17. }
18. return false;
19.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 20. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average DAC2 Metric
Calculation Algorithm
_ 0,00016000000000000000 -|— -C 0,00014000000000000000 ocn0,00012000000000000000 Л 0,00010000000000000000 I 0,00008000000000000000 t i 0,00006000000000000000 toni 0,00004000000000000000 о 0,00002000000000000000 i2 0,00000000000000000000
0 50 100 150 200 250 300 350 UML class diagram size (number of classes)
Рисунок 20. Зависимость времени работы алгоритма расчета метрики Average DAC2 от размера UML-диаграммы классов
Метрика DAC может быть рассчитана следующим образом (листинг 20): Листинг 20. Расчет метрики DAC
1.public int getDAC(Class classTemp, ClassDiagram classDiagram) {
2. int DAC = 0;
3. for (Entry<String,Attribute> entry: classTemp.getAttributes().entrySet()) {
4. Attribute attributeTemp = entry.getValue();
5. if ( searchClassByName(attributeTemp.getType(), classDiagram)) {
6. DAC++;
7. }
8. }
9. return DAC;
10.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 21. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average DAC Metric Calculation Algorithm
d
don0
c e
-ïs 0
e
me ti0
n o outi 0
c e
x 0 0,
00250000000000000000 00200000000000000000 00150000000000000000 00100000000000000000 00050000000000000000 00000000000000000000
0 50 100 150 200 250 300
UML class diagram size (number of classes)
350
Рисунок 21. Зависимость времени работы алгоритма расчета метрики Average DAC от размера UML-диаграммы классов
Метрика Average Size2 может быть рассчитана следующим образом (листинг 21):
Листинг 21. Расчет метрики SIZE2
1.public double getAverageSIZE2(ClassDiagram classDiagram) {
2. int classCount = classDiagram.getClasses().size();
3. int sumSIZE2 = 0;
4. for (Entry<String,Class> entry : classDiagram.getClasses().entrySet()) {
5. sumSIZE2 += getSIZE2(entry.getKey(),classDiagram);
6. }
7. double averageSIZE2 = roundUp(sumSIZE2/classCount,3);
8. return averageSIZE2; 9-}
10.public double getSIZE2(String classId, ClassDiagram classDiagram) {
11. Class classTemp = classDiagram.getClass(classId);
12. DACMetric dac = new DACMetric();
13. double SIZE2 = classTemp.getAttributes().size() + dac.calculate(classId, classDiagram);
14. return SIZE2;
15.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 22. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the Average SIZE2 Metric Calculation Algorithm
0,00020000000000000000 0,00018000000000000000 0,00016000000000000000 0,00014000000000000000 0,00012000000000000000 0,00010000000000000000 0,00008000000000000000 0,00006000000000000000 0,00004000000000000000 0,00002000000000000000 0,00000000000000000000
50 100 150 200 250 300 UML class diagram size (number of classes)
350
Рисунок 22. Зависимость времени работы алгоритма расчета метрики Average SIZE2 от
размера UML-диаграммы классов
classDiagram.getClasses().entrySet()) {
Метрика DSC может быть рассчитана следующим (листинг 22): Листинг 22. Расчет метрики DSC
1.public double getComplexity(ClassDiagram classDiagram) {
2. int c = classDiagram.getClasses().size(); //classes count
3. int i = classDiagram.getInterfaces().size(); // interfaces count
4. int r = classDiagram.getRelations().size(); // relations count
5. //count attributes
6. int a = 0; // attributes count
7. for (Entry<String, Class> entry
8. Class c0 = entry.getValue();
9. a += c0.getAttributes().size();
10. }
11. //count class methods
12. int m1 = 0;
13. for (Entry<String, Class> entry :
14. Class c0 = entry.getValue();
15. int m0 = c0.getOperations().size();
16. int m00 = 0;
17. //search interfaces, realized by this class
18. for (Entry<String, Relation> relEntry agram.getRelations()).entrySet()) {
19. Relation rel = relEntry.getValue();
classDiagram.getClasses().entrySet()) {
(classDi-
0
20. if (rel.getStartId().equals(c0.getId())) {
21. if (rel.getType().equals("realization")) {
22. Interface interTemp = classDi-agram.getInterfaces().get(rel.getEndId());
23. m00 += interTemp.getOperations().size();
24. }
25. }
26. }
27. ml += m0 - m00;
28. }
29. //count interface methods
30. int m2 = 0;
31. for (Entry<String, Interface> entry : classDi-agram.getInterfaces().entrySet()) {
32. Interface i0 = entry.getValue();
33. m2 += i0.getOperations().size();
34. }
35. double complexity = k1*c + k2*i + k3*r + k4*a + k5*m1+k6*m2;
36. complexity = roundUp(complexity,3);
37. return complexity;
38.}
График, отображающий зависимость времени работы алгоритма от размера UML-диаграммы классов показан на рис. 23. Время было рассчитано как среднее арифметическое времени, измеренного на 10 000 запусках алгоритма для UML-диаграмм классов размером 10, 20, 40, 100, 150, 200, 250, 300 классов.
Performance of the DSC Metric Calculation Algorithm
0,00300000000000000000
1 0,00250000000000000000 о
0,00200000000000000000 J 0,00150000000000000000
+3
о 0,00100000000000000000
3
ce0,00050000000000000000
X Ш
0,00000000000000000000
Рисунок 23. Зависимость времени работы алгоритма расчета метрики DSC от размера UML-диаграммы классов
UML class diagram size (number of classes)
4. Программное средство рефакторинга UML-диаграмм классов
Диаграмма классов программного средства рефакторинга UML-диаграмм классов UML Refactoring [15] изображена на рис. 24.
Класс Main.java — основной класс программы, отвечающий за инициализацию главной формы приложения, содержащий ссылки на контроллеры для главного окна, окна редактирования целевой функции и окна истории.
Класс UMLMap.java — класс, реализующий абстрактную структуру данных UML Map, содержит хеш-таблицу классов UML-диаграммы.
Класс ClassDiagram.java — класс, содержащий элементы UML-диаграммы классов: хеш-таблицу классов, хеш-таблицу интерфейсов, хеш-таблицу отношений, хеш-таблицу пакетов, ссылку на корневой пакет root.
Класс Class.java содержит хеш-таблицы методов класса, его атрибутов, id класса, его имя и месторасположение.
Класс Interface.java содержит хеш-таблицы методов интерфейсов, его id и имя.
Класс Relationjava хранит id начального класса и конечного класса/метода. От него наследуются классы Aggregation.java, Composition.java, Dependency.java, Gen-eralization.j ava, Realization.j ava.
Класс Metric.java отвечает за расчет метрик. ClassDiagramMetric.java — наследует Metric.java, метрика уровня класса рассчитывается для класса. От ClassDiagramMetric.java наследуется класс DACMetric.java. DiagramLevelMetric.java наследует Metric.java, метрика уровня диаграммы, рассчитывается для диаграммы в целом. От класса DiagramLevelMetric.java наследуются следующие классы: Clas-sesMetric.java, InterfacesMetric.java, RelationsMetric.java, DSCMetric.java, AverageC-BO.java, AverageDIT.java, AverageNOC.java, AverageDACMetric.java, Aver-ageNLM.java, AverageNOMMetric.java, DAC2Metric.java, SIZE2Metric.java.
Класс Analyzer.java проводит анализ диаграммы классов и выдает для заданного списка рефакторингов на выходе список трансформаций, снижающих значение целевой функции.
Класс Transformator.java применяет к диаграмме классов выбранную трансформацию.
Класс RefactoringSeeker.java проводит поиск элементов диаграммы классов, применение к которым заданного рефакторинга снижает значение целевой функции. От него наследуются классы FacadeRefactoringSeeker.java, InterfaceRefactor-ingSeeker.j ava, StrategyRefactoringSeeker.j ava.
Рисунок 24. Диаграмма классов программного средства UML Refactoring
Класс Refactoring.java содержит такие атрибуты, как type, parameters, а также метод execute(), который производит преобразование выбранной диаграммы классов над подмножеством ее элементов. Класс Refactoring.java наследуют Fa-cadeRefactoring .j ava, InterfaceRefactoring.j ava, StrategyRefactoring.j ava.
Класс TranslatorFromXMI.java отвечает за обработку UML-диаграммы классов, сохраненной в формате XMI, и трансляцию ее в абстрактную структуру данных UMLMap.
Класс TranslatorToXMI.java отвечает за экспорт UML-диаграммы классов из абстрактной структуры данных в формат XMI.
Для проведения анализа объектно-ориентированной архитектуры программного обеспечения был предоставлен исходный код библиотеки ArPlatform на языке C++.
Для построения на основе исходного кода соответствующей UML-диаграммы классов был разработан прототип плагина на языке C++ для компилятора с открытым исходным кодом CLANG [16], основанного на виртуальной машине низкого уровня LLVM (Low Level Virtual Machine).
Разработанный прототип плагина CPPToXMI позволяет строить на основе исходного кода программы на языке C++ его UML-диаграмму классов в формате XMI, разработанным группой OMG для обмена UML-моделями между программными средствами.
Алгоритм работы плагина может быть описан следующим образом (листинг 23):
Листинг 23. Алгоритм работы прототипа плагина CLANG для построения UML-диаграммы классов в формате XMI для исходного кода на языке С++
1.//class diagram to be created
2.ClassDiagram diagram = new ClasasDiagram()
3.std::list<list<string>> agregations = new std::list<list<string>>()
4.for each CXXRecordDecl RD
5. if RD->isClass()
6. bool class_is_abstract = get_is_abstract(RD)
7. attributes_temp = get_attributes(RD)
8. methods_temp = get_methods(RD)
9. //create aggregation pairs
10. for each attribute in attributes_temp
11. list<string> agregation_pair = new list<sting>()
12. agregation_pair.push_back(attribute_class_name)
13. agregation_pair.push_back(class_temp.get_is())
14. agregations.push_back(agregation_pair)
15. if (!class_is_abstract & attributes_temp.size>0)
16. //get class name, generate id
17. class_temp.set_name(get_class_name(RD))
18. class_temp.set_id(generate_ID())
19. class_temp.set_is_abstract(class_is_abstract)
20. class_temp.add_methods(methods_temp)
21. class_temp.add_attributes(attributes_temp)
22. diagram.add_class(class_temp)
23. if (RD->getNumBases()>0)
24. //add generalization relations to diagram
25. for each base in RD->getNumBases()
26. Generalization relation = new Generalization^
27. relation.set_start_id(class_temp.get_id())
28. relation.set_end_id(get_parent_id())
29. diagram.add_relation(relation)
30. //add dependency relations
31. for each method in methods_temp
32. if method.hasBody()
33. Stmt body = method.getBody()
34. for each child in body
35. if child is MemberExpr
36. Dependency relation = new Dependency()
37. relation.set_start_id(class_temp.get_id())
38. relation.set_end_id(get_id(child))
29.else
30. //add interface
31. Interface interface_temp = new Interface()
32. interface_temp.set_name(get_name(RD))
33. interface_temp.set_id(generate_id())
34. interface_temp.add_methods(get_methods(RD))
35. diagram.add_interface(interface_temp)
36.//create aggregation relations
37.for each aggregation_pair in aggregations
38. class_name = agregation_pair.front()
39. string end_id = agregation_pair.back()
40. if (diagram.has_class(class_name))
41. Aggregation relation = new Aggregation()
42. relation.set_id(generate_id())
43. relation.set_start_id(diagram.get_id(class_name))
44. relation.set_end_id(end_id)
45. diagram.add_relation(relation)
46.save_diagram(diagram.to_xmi(), path)
Алгоритм метода diagram.to_xmi() может быть описан следующим образом: Листинг 24. Алгоритм работы прототипа плагина CLANG для построения UML-диаграммы классов в формате XMI для исходного кода на языке С++
//add XMI prefix
string str = prefix
for each interface in interfaces
str+= interface.to_xmi() for each class in classes str+=class.to_xmi() for each relation in relations
if (relation.get_start_id() == class.get_id()) str+=relation.to_xmi() //add XMI suffix str+=suffix return str
Разработанный прототип плагина позволяет строить модель исходного кода на языке С++ для его последующего анализа при помощи инструментального средства UML Refactormg. Для учета распределения классов и интерфейсов по пакетам требуется дальнейшая доработка плагина.
Затем после ручной доработки была получена UML-диаграмма классов библиотеки ArPlatform. Фрагмент диаграммы классов представлен на рис. 25.
Рисунок 25. Фрагмент UML-диаграммы классов для библиотеки АгРШАзгт
Результат первичного анализа диаграммы классов библиотеки ArPlatform при помощи программного средства UML Refactoring представлен на рис. 26. Метрики, рассчитанные для диаграммы классов, представлены на рис. 27.
Рисунок 26. Результат первичного анализа UML-диаграммы классов библиотеки АгРШАзгт при помощи программного средства ПЫЪ Refactoring
Metrics
№ Name Value
1 Classes count 106.0
2 Interfaces count 0.0
3 Relations count 118.0
4 Avg. DIT 0.434
5 Avg. CBO 1.66
6 Avg. NOC 0.283
7 Avg. NOM 9.887
8 Avg. NLM 0.0
9 Avg. DAC 0.0
10 DAC 0.0
11 SIZE2 1.0
12 DSC 131.31
Рисунок 27. Метрики, рассчитанные для исходной UML-диаграммы классов библиотеки ArPlatform при помощи программного средства UML Refactoring
4.1. Рефакторинг с выбранной в качестве целевой функции метрикой DSC
Рассмотрим трансформации, рекомендованные программным средством UML Refactoring к применению для различных целевых функций рефакторинга.
Метрика DSC (Diagram Structural Complexity) измеряется следующим образом: Путь дана диаграмма классов d = {С, I, R, Р}.
Тогда метрика DSC(d) определяет сложность диаграммы классов d следующим образом:
Dsc(d) =| с |+111+1 r | +х;=0 i А | +х;=о i Мг | +х;=0 i М; i , (i>
где DSC(d) — сложность UML-диаграммы классов d; С — множество классов диаграммы d; I — множество интерфейсов диаграммы d; R — множество отношений диаграммы d; Д — множество атрибутов класса с е С, i е 0,..., п; М — множество методов класса с е С, i е 0,..., п, за исключением методов, принадлежащих реализуемым классов oi интерфейсам ц, l е 0,..., к, где к — число реализуемых классов интерфейсов; М) — множество методов интерфейса сз е I, j е 0,..., т.
Для анализа были заданы следующие значения весов (рис. 28) — в качестве цели рефакторинга была выбрана минимизация количества отношений в диаграмме классов:
к = 0.01; к = 0.01; к = 10; к4 = 0.01; к = 0.01; к = 0.01.
Рисунок 28. Метрика DSC, выбранная в качестве целевой функции рефакторинга с весами k = 0.01; k = 0.01; k3 = 1.0; k4 = 0.01; £5 = 0.01; £6 = 0.01
Трансформации, рекомендованные к применению, представлены в табл. 4.
Таблица 4. Трансформации, предложенные для библиотеки ArPlatform инструментальным средством UML Refactoring для метрики DSC в качестве целевой функции рефакторинга
№ Трансформация Подмножество элементов диаграммы ¥(d)
1. Façade transformation Inner Classes: ArDictionary; AddingMultiLinkF orm; ArEntity; ArTableModel; ArEntityList. -1.93999
2. Façade transformation InnerClasses: ArTransactionProcess; ArMultilink; ArEntity; ArMessage; ArEntityList; ArTransaction; ArManyToOneLink; ArOneToManyLink; MappingConfig; AeEntityParameters; ArLocation; ArNotifier. -12.8700
3. Façade transformation InnerClasses: AddingMultiLinkF orm; ArDictionary; ArEntity; ArTableModel; ArEntityList. -1.9399
Таблица 4. Продоллжение
№ Трансформация Подмножество элементов диаграммы ¥(d)
4. Façade transformation Inner Classes: ArEntity; ArDictionary; ArTransactionProcess; AddingMultiLinkF orm; ArEntityDialog; ArEntityForm; DbConnectionParametersModel; ArTableModel; ErEntityist; ArTransaction; TransactionCommand; ArNotifier. -9.8700
5. Façade transformation InnerClasses: ArMessage; ArTransactionProcess; ArTransaction; ArEntityParameters; ArLocation. -2.9399
6. Façade transformation InnerClasses: ArEntityDialog; ArEntity; ArEntityForm; DbConnectionParametersModel; ArEntityList. -2.9399
7. Façade transformation Inner Classes: ArEntityForm; ArEntity; ArEntityDialog; ArTableModel. -0.9499
8. Façade transformation Inner Classes: DBConnectionParametersModel; ArEntity; ArentityDialog; ArEntityList. -2.9499
9. Façade transformation Inner Classes: ArTableModel; Ardictionary; AddingMultiLinkF orm; ArEntity; ArEntityForm; ArEntityList. -2.9300
10. Façade transformation Inner Classes: ArEntityList; ArDictionary; ArAbstractEntityList; ArTransactionProcess; AddingMultyLinkF orm; ArEntity; ArEntityDialog; DBConnectionParametersModel; ArTableModel; ArEntityListItem; TransactionCommand; ArNotifier. -6.8700
Таблица 4. Окончание
№ Трансформация Подмножество элементов диаграммы ¥(d)
11. Façade transformation Inner Classes: ArTransaction; ArTransactionProcess; ArEntity; ArMessage; ArEntityParameters; ChatLocalListener; ArLocation. -4.9200
12. Façade transformation Inner Classes: ArEntityParameters; ArTransactionProcess; MainWindow; ArMessage; DbProcess; ArTransaction; ArLocation; ArNotifier. -6.9099
13. Façade transformation InnerClasses: ChatLocalListener; ArTransaction; ArLocation. -0.9600
14. Façade transformation Inner Classes: TransactionCommand; ArEntity; ArEntityList; ArNotifier. -1.9499
15. Façade transformation Inner Classes: ArLocation; ArTransactionProcess; ArMessage; ArTransaction; DbConnection; ArEntityParameters; ChatLocalListener; ArNotifier. -5.9099
16. Façade transformation Inner Classes: ArNotifier; ArMultiLink; ArTransactionProcess; ArEntity; MainWindow; DbProcess; ArEntityList; ArManyToOneLink; ArOneToManyLink; DbConnection; MappingConfig; ArEntityParameters; TransactionCommand; ArLocation. -10.8500
Окончательное решение о применении той или иной трансформации к диаграмме классов должно приниматься разработчиком. Выбранная в качестве приме-
ра цепочка трансформаций показана на рис. 29. В результате значение целевой функции рефакторинга снизилось с 131.31 до 117.53 (рис. 30). Число отношений снизилось со 118 до 104.
Рисунок 29. История трансформаций, примененных к исходной диаграмме с метрикой DSC в качестве целевой функции рефакторинга
Рисунок 30. Результат применения к исходной диаграмме двух трансформаций
4.2. Рефакторинг с выбранной в качестве целевой функции метрикой Average CBO
Метрика CBO (Coupling Between Objects) предложена Чидамбером и Кемерером. Измеряется как число не связанных наследованием классов, с которыми связан данный класс. Отражает степень взаимосвязанности компонентов системы. Трансформации, рекомендованные к применению системой, представлены в табл. 5.
Таблица 5. Трансформации, предложенные для библиотеки ArPlatform инструментальным средством UML Refactoring для метрики Average CBO в качестве целевой функции рефакторинга
№ Трансформация Подмножество элементов диаграммы ¥(d)
1. Façade Transformation Inner Classes: ArNotifier ArMultiLink ArTransactionProcess ArEntity MainWindow DbProcess ArEntityList ArManyToOneLink ArOneToManyLink DbConnection MappingConfig ArEntityParameters TransactionCommand ArLocation -0.22099
2. Façade Transformation Inner Classes: ArLocation ArTransactionProcess ArMessage ArTransaction DbConnection ArEntityParameters ChatLocalCenter ArNotifier -0.127
3. Façade Transformation Inner Classes: TransactionCommand ArEntity ArEntityList ArNotifier -0.05299
4. Façade Transformation Inner Classes: ChatLocalCenter ArTransaction ArLocation -0.03400
5. Façade Transformation Inner Classes: ArEntityParameters ArTransactionProcess MainWindow ArMessage DbProcess ArTransaction ArLocation ArNotifier -0.14599
6. Façade Transformation Inner Classes: DbConnection Mapper DbSQLCommandThread ArLocation ArNotifier -0.01499
Таблица 5. Продолжение
№ Трансформация Подмножество элементов диаграммы ¥(d)
7. Façade Transformation Inner Classes: ArTransaction ArTransactionProcess ArEntity ArMessage ArEntityParameters ChatLocalCenter ArLocation -0.10899
8. Façade Transformation Inner Classes: ArEntityList Ardictionary ArAbstractEntityList ArTransactionProcess AddingMultiLinkF orm ArEntity ArEntityDialog DbConnectionParametersModel ArTableModel ArentityListItem TransactionCommand ArNotifier -0.14599
9. Façade Transformation Inner Classes: ArentityForm Arentity ArEntityDialog ArTableModel -0.03400
10. Façade Transformation Inner Classes: ArEntityDialog ArEntity ArEntityForm DbConnectionParametersModel ArentityList -0.07099
11. Façade Transformation Inner Classes: ArMessage ArTransactionProcess ArTransaction ArEntityParameters ArLocation -0.07099
12. Façade Transformation Inner Classes: ArEntity; ArDictionary; ArTransactionProcess; AddingMultiLinkF orm; ArEntityDialog; ArEntityForm; DbConnectionParametersModel; ArTableModel; ArEntityList; ArTransaction; TransactionCommand; ArNotifier -0.20199
Таблица 5. Окончание
№ Трансформация Подмножество элементов диаграммы ¥(d)
13. Façade Transformation Inner Classes: AddingMultiLinkF orm ArDictionary ArEntity ArTableModel ArEntityList -0.05299
14. Façade Transformation Inner Classes: ArTransactionProcess; ArMultiLink ArEntity ArMessage ArEntityList ArTransaction ArManyToOneLink MappingConfig ArEntityParameters ArLocation ArNotifier -0.258
15. Façade Transformation Inner Classes: ArDictionary AddingMultiLinkF orm ArEntity ArTableModel ArEntityList -0.05299
16. Interface transformation Class: ArTransactionProcess -0.05599
17. Interface transformation Class: FieldParameters -0.02800
18. Interface transformation Class: ArEntityParameters -0.01800
19. Interface transformation Class:ArDbProcess -0.01800
20. Interface transformation Class: ArEntityDialog -0.00899
21. Interface transformation Class: ArEntity -0.08499
22. Interface transformation Class: ArNotifier -0.03699
23. Interface transformation Class: ArDictionary -0.00899
24. Interface transformation Class: ArLocation -0.04699
25. Interface transformation Class: ArTransaction -0.02800
26. Interface transformation Class: ArEntityList -0.04699
27. Interface transformation Class: ArTableModel -0.00899
Выбранная в качестве примера цепочка трансформаций показана на рис. 31.
В результате значение целевой функции рефакторинга снизилось с 1.664 до 1.35 (см. рис. 32).
Проведенный при помощи программного средства UML Refactoring анализ показал, что применение паттернов проектирования «Фасад» и «Введение интерфейса» к архитектуре позволит улучшить показатели метрик DSC и Average CBO, влияющие на такие свойства архитектуры, как гибкость и сопровождаемость.
13 History - □ x
[ftj List of the refactorings, which have been applied to the current class diagram:
№ Transformation
1 Facade transformation
Parameters
Inner Classes:
ArNotifer;
ArMultiLink;
ArTransactionProcess;
arentity;
mainwindow;
DbProcess;
ArEntity List;
ArManyToOneLink;
ArOneToManyLink;
DbConnection;
mappingconfig;
arentityparameters:
TransactionCommand;
ArLocation;
Facade transformation
Inner Classes: Field List; FieldParameters;
Рисунок 31. История трансформаций, примененные к исходной диаграмме с метрикой Average CBO в качестве целевой функции рефакторинга
■ UMt reTactonng Не Edit View Hdp
Н а
r.^form.bom Model Eipkxer
N» Maro« Parameter» Delta F(d) » Model
MdingMukiüntfenn; ► Qmam
■ЬшМММ:
► g Af AbstractEnttylistltemModel
► g AiOneToManybnk
Metrics > H ArManyloOneOnk
Н> Name Vahle * Q TramacbonCommand
1 Claiieicount кал ► H Aftntitybnktet
2 Interface» count OX) ► H FacadeCiMt22S
Э Retatom count 1040 ► Q FacadeClan267
4 Avg DIT 0426 » CD "9»i'b
S Avg. CBO use ► g AddmgMultL»*form
6 Avg NOC CL278 ► § ArEntitybstform
7 Avg NOW 9.70« ► ÜDbProcets
8 Avg NIM 00 ► @ AfintityDiatog
В Avg DAC 00 ► В procetsform
10 DAC 10 ► В Art nt it/form
11 SIZK 1Л » Quit
12 DSC 117/49 » Q ArBaucfntityOnk
» § ArSmgMjnk
Рисунок 32. Результат применения к исходной диаграмме двух трансформаций
5. Методика рефакторинга иМЬ-диаграмм классов при помощи программного средства иМЬ Refactoring
На основе разработанных программно-математических средств можно сформулировать методику рефакторинга ИМЬ-диаграмм классов с учетом заданных критериев качества при помощи программного средства ИМЬ Я^аЛои^. Данная методика состоит из следующих этапов:
1. Экспорт UML-диаграммы классов из инструментального средства проектирования UML-модели в формат XMI.
2. Импорт UML-диаграммы классов, представленной в формате XMI, в программное средство UML Refactoring.
3. Программное средство UML Refactoring проводит анализ UML-диаграммы классов: рассчитывает объектно-ориентированные метрики, строит дерево иерархии классов.
4. Выбирается целевая функция для рефакторинга.
5. Программное средство UML Refactoring производит поиск трансформаций, снижающих значение целевой функции рефакторинга и выводит предложенные варианты на экран.
6. В случае, если выбрана одна из трансформаций, программное средство автоматически применяет ее к диаграмме классов и выполняется переход к п. 3.
По окончании процесса рефакторинга изменения в XMI-файле, а затем импортирует его в инструментальное средство проектирования UML-модели для дальнейшего проектирования.
6. Заключение
В работе проведен анализ методов основных подходов к формальному описанию, трансформации и рефакторингу UML-диаграмм классов. Рассмотрены основные стандарты модельно ориентированного подхода к разработке программного обеспечения, указана роль в рамках данного подхода задачи рефакторинга UML-диаграмм классов. Также в работе проанализированы основные подходы к заданию целевой функции рефакторинга UML-диаграмм классов.
Для решения задачи рефакторинга UML-диаграмм классов разработаны математические методы:
- разработано алгебраическое описание UML-диаграмм классов;
- создан способ описания структурной семантики UML-диаграммы классов;
- формально описаны семантически эквивалентные трансформации «Введение интерфейса», «Фасад», «Стратегия»;
- разработана абстрактная структура данных UML Map, позволяющая представлять UML-диаграмму классов в оперативной памяти компьютера, рассчитывать метрики, производить поиск элементов диаграммы и ее трансформацию.
Кроме того, в работе разработаны алгоритмы:
- трансформации UML-диаграмм классов «Введение интерфейса», «Фасад», «Стратегия»;
- рефакторинга UML-диаграмм классов CDTA;
- поиска подмножеств UML-диаграммы классов, применение к которым трансформации «Введение интерфейса»/«Фасад»/«Стартегия» снижает значение целевой функции;
- расчета объектно-ориентированных метрик Average CBO, Average DIT, Average NOC, Average DAC, Average NLM, Average NOM, DAC2, SIZE2, DSC на основе АСД UML Map.
На основе созданных математических методов и алгоритмов спроектировано, разработано, отлажено и внедрено программное средство рефакторинга UML-диаграмм классов UML Refactoring.
Кроме того, предложена методика рефакторинга UML-диаграмм классов при помощи программного средства рефакторинга UML Refactroring
Программу UML Refactoring можно скачать на сайте: www.uml-refactoring.ru.
Литература
[1] OMG Model Driven Architecture (http://www.omg.org/mda).
[2] OMG Meta Object Facility Specification 2.5.1. (http://www.omg.org/spec/MOF/2.5.1/).
[3] OMG Unified Modelling Language UML. Version 2.5 (http://www.omg.org/spec/UML/2.5).
[4] XML Metadata Interchange (XMI) Specification. Version 2.4.2 (http://www.omg.org/ spec/XMI/2.4.2).
[5] Object Constraint Language Specification. Version 2.4. (http://www.omg.org/spec/OCL/2.4).
[6] Gamma E., Richard H., Ralph J., and John V. Design patterns: Abstraction and reuse of object-oriented design. — Springer Berlin Heidelberg, 1993.
[7] Fowler M. Refactoring: Improving the Design of Existing Code. — Boston M. A. : Addison-Wesley, 2000.
[8] Kerievsky J. Refactoring to Patterns. — Boston M. A. : Addison-Wesley, 2004.
[9] МартинР., МартинМ. Принципы, паттерны и методики гибкой разработки на языке C#: пер. с англ. — СПб. : Символ-Плюс, 2011.
[10] Vathsavayi S. et al. Tool support for software architecture design with genetic algorithms // 2010 Fifth International Conference on Software Engineering Advances (ICSEA). — IEEE, 2010. P. 359-366.
[11] O'Keeffe M., Cinneide M. O. Towards automated design improvements through combinatorial optimization // Workshop on Directions in Software Engineering and Environments (WoDi-SEE'04), W2S International Conference on Software Engineering. 2004. P. 75-82.
[12] O'Keeffe M., Cinneide M. O. Search-based software maintenance // Proceedings of the 10th European Conference on Software Maintenance and Reengineering, CSMR 2006. — IEEE, 2006. P. 249-260.
[13] Mancoridis S. et al. Using automatic clustering to produce high-level system organizations of source code // Proceedings. 6th International Workshop on Program Comprehension, IWPC'98. — IEEE, 1998. P. 45-52.
[14] Дерюгина О. А. Семантика и семантически эквивалентные трансформации UML-диаграмм классов // Труды МФТИ. 2015. Т. 7. № 2. С. 146.
[15] Дерюгина О. А., Никульчев Е. В. Инструментальное средство автоматизированного ре-факторинга UML-диаграмм классов по заданным критериям качества // Кибернетика и программирование. 2017. № 1. С. 107-118.
[16] Clang: C Family Language Frontend for LLVM [Электронный ресурс]. URL: http://clang.llvm.org
Автор:
Ольга Александровна Дерюгина — преподаватель кафедры «Управление и моделирование
систем», Московский технологический университет (МИРЭА)
Mathematical and software means of the UML class diagram refactoring
O. A. Deryugina
Moscow Technological University (MIREA) Prospekt Vernadskogo, 78, Moscow, Russia, 119454
e-mail: [email protected]
Abstract. The paper discusses the problem of the UML class diagram refactoring. UML class diagrams are inevitable for the design of the software Platform Independent Model (PIM) at the MDA approach proposed by the OMG organization. The article formalizes the problem of the UML class diagram refactoring, proposes mathematical methods of the UML class diagram structural semantics calculation and UML class diagram transformation. It also presents algorithms of UML class diagram transformation and refactoring and algorithms of the object oriented metrics calculation. The article proposes the UML Refactoring software tool, which provides UML class diagram refactoring. In conclusion, it formulates the methods of the UML class diagram refactoring using the UML Refactoring software tool.
Key words: UML, XMI, software design, software architecture, MDA, refactoring, UML class diagram refactoring
References
[1] http://www.omg.org/mda
[2] http://www.omg.Org/spec/MOF/2.5.1/
[3] http://www.omg.Org/spec/UML/2.5
[4] http://www.omg.org/spec/XMI/2.4.2
[5] http://www.omg.org/spec/OCL/24
[6] Gamma E., Richard H., Ralph J., and John Vl. (1993) Design patterns: Abstraction and reuse of object-oriented design. — Springer Berlin Heidelberg.
[7] Fowler M. (2000) Refactoring: Improving the Design of Existing Code. Boston M. A., Addi-son-Wesley.
[8] Kerievsky J. (2004) Refactoring to Patterns. Boston M. A., Addison-Wesley.
[9] Martin R., Martin M. (2011) Printsipy, patterny i metodiki gibkoy razrabotki na yazyke C#. Saint-Petesburg, Simvol-Plyus. 768 p. [In Rus]
[10] Vathsavayi S. et al. (2010) Tool support for software architecture design with genetic algorithms. 2010 Fifth International Conference on Software Engineering Advances (ICSEA), p. 359-366.
[11] O'Keeffe M., Cinnéide M. O. (2004) Towards automated design improvements through combinatorial optimization. In book: Workshop on Directions in Software Engineering and Environments (WoDiSEE'04), W2S International Conference on Software Engineering. p. 75-82.
[12] O'Keeffe M., Cinnéide M. O. (2006) Search-based software maintenance. Proceedings of the 10th European Conference on Software Maintenance and Reengineering, CSMR 2006, 2006. p. 249-260.
[13] Mancoridis S. et al. (1998) Using automatic clustering to produce high-level system organizations of source code. Proceedings. 6th International Workshop on Program Comprehension, IWPC'98. p. 45-52.
[14] Deryugina O. A. (2015) TrudyMFTI, 7(2):146. [In Rus]
[15] Deryugina O. A., Nikulchev E. V. (2017) Kibernetika iprogrammirovaniye, 1:107-118.
[16] http://clang.llvm.org