Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Применение объектно-ориентированного подхода при проектировании информационной системы(SPARX Enterprise Architect)

Содержание:

Введение

Разработка программного обеспечения, в частности информационных систем в современном мире не обходится без применения объектно ориентированных методов проектирования. Необходимость изменений, исправлений и сопровождения программных продуктов диктует необходимость понятного, удобного и универсального подхода к их проектированию. Таким подходом стал объектно-ориентированный подход в основе которого лежит структурное объединение данных и алгоритмов в классы(объекты – экземпляры классов) по функциональным и логическим критериям. Важность этого подхода и его понимания в разработке программных продуктов чрезвычайно важна для любого специалиста в отрасли.

Современное объектно-ориентированное программирование, а в применении к программному обеспечению это именно программирование, являет собой совокупность инкапсуляции, наследования и полиморфизма. Современные стандарты программирования считают множественное наследование плохой практикой, впрочем допуская множественное наследование интерфейсов(для языка С++ полностью виртуальных или абстрактных классов).

Для раскрытия темы данной работы и выполнения методических требований представляется целесообразным рассмотреть три разных программных продукта реализующих объектно-ориентированный подход для разработки программных продуктов. И хотя тематика данной работы не предполагает конкретных проектных решений, она, тем не менее, не исключает его. Рассмотреть и проанализировать в достаточной мере преимущества и недостатки не применяя конкретных возможностей на практике автор этой работы считает сомнительным решением, поэтому в данной работе будут рассмотрены два программных продукта реализующих объектно-ориентированный подход и одно решение будет разработано самостоятельно.

Глава 1. Обзор программных продуктов

§ 1.1 SPARX Enterprise Architect

Возможности выбора решений для проведения данной работы ограниченны коммерческой составляющей, часть программных продуктов является платными и использовать их возможности нет. Тем не менее, некоторые производители представляют trial-версии, в частности речь о первом продукте, подлежащем анализу – SPARX Enterprise Architect.

Данный программный продукт достаточно современный, версия 2019 года, имеет хороший интерфейс, развернутую систему онлайн документации. Тот факт, что документация, как и весь интерфейс, доступна только на английском языке сложно оценить однозначно. С одной стороны, некоторые аспекты могут быть непонятны и неочевидны, с другой стороны русский перевод, в зависимости от качества разумеется, может внести еще больше неясности, а в крайнем случае даже полностью сделать материал нечитаемым. Поскольку английский язык де факто является международным языком общения, а в области IT фактически обязательным, а в программировании даже безальтернативным, рассматривать этот языковой момент в качестве недостатка было бы неразумно. Тем не менее кодировка utf-8 поддерживается, что не исключает использования отличных от основанных на латинской письменности языков.

В пакете, доступном, для скачивания также доступен демонстрационный проект с развернутыми комментариями и инструкциями. К отличительным особенностям можно отнести тот факт, что реализовано данное программное решение в нативном исполняемом виде, а генерация кода осуществляется практически на всех ныне применяемых языках программирования, наиболее известные и используемые из которых C++, C#, Java, Delphi.

Рассматриваемое программное обеспечение поддерживает 13 типов диаграмм UML, де-факто стандарта для построения объектно-ориентированного программного обеспечения. В целом можно оценить как серьезный продукт для решения широкого спектра задач проектирования промышленного уровня.

Описать все возможности данного программного продукта в рамках этой работы и данного обзорной главы не представляется возможным, наиболее важные и применяемые для решения задач данной работы будут рассмотрены далее.

§ 1.2 Microsoft Visual Studio

Во избежание повторения описания одинакового функционала и для создания широты обзора в данной работе было принято решение выбрать непохожие решения. Для реализации последней задачи данного исследования, помимо SPARX Enterprise Arhitect будет использована Microsoft Visual Studio Community Edition. Распространяемый бесплатно пакет программного обеспечения для решения широкого спектра задач с поддержкой множества языков программирования, разумеется, реализующий парадигмы ООП в полном объеме. На рынке программного обеспечения, RAD и CASE систем сложно назвать более всеобъемлющее решение.

MS Visual Studio Community Edition также имеет компоненты для проектирования UML «Конструктор классов» эти возможности будут рассмотрены как и решение от SPARX Systems. Также в данной работе будут использованы другие возможности, а именно создание проекта Windows Forms платформы .NET на языке программирования С#. Данный язык программирования реализованный в общеязыковой среде исполнения(CLR – Common Language Runtime) сочетает возможности объектно-ориентированной разработки, реализуя все её парадигмы, визуальный RAD стиль, позволяя в рамках данный работы получить достаточные представления о практических и теоретических аспектов процесса создания программного обеспечения. Язык программирования C# является управляемым, что освобождает от дополнительных сложностей связанных с управлением памятью благодаря Сборщику Мусора(Garbage Collector).

Анализируя остальные возможности MS Visual studio, стоит отметить достаточно проработанные возможности IDE, такие как отладочные механизмы, IntelliSense(система контекстной помощи при написании программного кода), настраиваемость, гибкость.

В целом, решение от Microsoft можно оценить очень высоко, а годы наработок не прошли даром для компании из Редмонда. Недостатком можно считать лишь высокие, для офисного компьютера, системные требования, на процессорах, в зависимости от решаемой задачи, низкого и средне-низкого ценового сегмента использование данного программного продукта может быть затруднено, в некоторых случаях крайне затруднено.

§ 1.3 UML Modeller

Прежде чем перейти непосредственно к решению поставленных задач, было бы разумно конкретизировать и описать последний пункт задачи, а именно разработка собственного решения для проектирования информационных систем с использованием объектно-ориентированного подхода. Данная задача не предусматривает создание всеобъемлющего решения, но должна продемонстрировать основные концепции в ограниченном возможностями данной работы пространстве.

Целью является создание desktop приложения Windows с графическим пользовательским интерфейсом, позволяющим пользователю создавать «мышкой» диаграммы классов.

Название проекта носит условный характер, разрабатывается исключительно в образовательных целях.

§ 1.4 Выводы

Таким образом были обозначены цели и основные этапы данной работы, перечислены программные продукты подлежащие анализу.

Глава 2. Разработка диаграмм UML

Существует 3 способа использования UML – первый, от руки на листе бумаги или маркерно-магнитной доске и применяется для черновиков, набросков и при обсуждениях; второй для разработки проектной документации, предварительной генерации части кода; третий как языка программирования с полной генерацией программного кода.[1]

В данной работе используется второй подход. Диаграммы UML созданные в Sparx Enterprise Architect будут служить иллюстрацией и наглядным представлением возможностей программного продукта, также для предварительной генерации части программного кода на языке C#. В данной части работы разрабатываемые диаграммы классов носят условный характер и не соответствую реальному программному решению.

§ 2.1 Классы и интерфейсы

Если кто-нибудь подойдет к вам в темном переулке и спросит: «Хотите

посмотреть на диаграмму UML?», знайте – скорее всего, речь идет о диаграмме класса.[2]

В данной работе не будут рассмотрены аспекты визуального моделирования кроме тех без которых нельзя обойтись, а такие как последовательность действий и движение по веткам интерфейса меню будут опущены как несущественные.

Основой моделирования диаграммы классов в SPARX Enterprise Architect является Element, который можно настроить для выражения необходимых сущностей. В целях удобства будут последовательно рассмотрены используемые типы элементов.

Элемент, как указывалось выше может быть представлен, например, типом «Class», «Use Case», «Node» или «Component». Именно тип «Class» станет отправной точкой данного исследования.

Элемент типа «Class» был смоделирован как показано на рисунке 1.

Рисунок 1. Диаграмма классов:

класс и реализуемые интерфейсы.

Справа расположен элемент типа «Class», стоит обратить внимание что его название совпадает с именем типа, а слева расположены два элемента типа «Interface».

Отношения между данными элементами выражены стрелками, выражающими тип «Generalization» или обобщение, то есть в терминологии C++ можно сказать что Class является наследником двух полностью виртуальных базовых классов IDraw и IManage. Поскольку в C++ нет интерфейсов, такая возможность реализована именно через виртуальные классы. Но в применяемом для целей данной работы языке C# интерфейсы можно объявлять явно.

Стоит обратить внимание на то что статические свойства и методы класса подчеркиваются. Видимость, согласно стандарту, UML обозначена для PUPLIC и PRIVATE символами «+» и «-» соответственно.

В данном примере показан двусвязный список, управление которым осуществляется через интерфейс IManage и отрисовка класса на форме через интерфейс IDraw.

§ 2.2 Агрегация и Композиция

Выше было уже показан тип ассоциаций «обобщение» для отображения связи класса и его интерфейсов. Следующие типы ассоциаций, рассматриваемые в данной работе – «Агрегация» и «Композиция» изображены на рисунке 2.

Рисунок 2. Ассоциации – обобщение, агрегация, композиция

Вызывает некоторую сложность дифференцирование между двумя этими последними. До появления языка UML вопрос о различии между агрегацией и ком позицией у аналитиков просто не возникал. Осознавалась подобная неопределенность или нет, но свои работы в этом вопросе аналитики совсем не согласовывали между собой. В результате многие разработчики считают агрегацию важной, но по совершенно другой причине.

Язык UML включает агрегацию но семантика ее очень расплывчата.[3]

В разрабатываемой модели экземпляры класса Feature содержатся в контейнере List<Feature>, который является частью Class. Экземпляры класса Feature могут находиться в любом количестве во владении любых других объектов – поэтому применена Агрегация. Однако, перечисления Visability и Type могут быть лишь частью класса Feature поэтому применяется более специализированная Композиция.

§ 2.3 Перечисления

Консорциум OMG определяет Перечисления как тип данных, значения которого перечислены в модели в качестве литералов.[4]

Показанные на рис. 2 перечисления(enumeration) введены в модель для иллюстрации применения Композиции, однако, здесь стоит отметить что для управляемых языков программирования, по крайней мере точно известно про C#, перечисления(Enum) являются классами, соответственно могут быть инстанциированы как экземпляры класса. Допустимо было и на этапе моделирования использовать их как классы.

§ 2.4 Редактирование и генерация кода

В SPARX Enterprise Architect, как уже отмечалось выше есть возможность генерировать программный код для последующего использования.

В данной работе используется подход с частичной генерацией кода, однако, существует возможность добавлять код прямо в интерфейсе программы. На рисунке 3 показано что встроенный редактор кода поддерживает структурированный программный код, имеет подсветку синтаксиса.

Здесь не будут рассмотрены детали реализации, добавленный в редакто программный код имеет условный характер.

Рисунок 3. Добавление программного кода в модель

На рисунке 4 представлен интерфейс создания программного кода.

Рисунок 4. Интерфейс генерации кода.

Сгенерированный код соответствует тому что было спроектировано в программе. Объявленные свойства элемента Class получили следующий программный вид:

public class Class : IManage, IDraw {

private static int count;

private static Class start_instance;

private static Class current_instance;

private int ID;

private Class instance;

private Class next_instance;

private Class prev_instance;

private List<Feature> features;

Как видно из програмного кода, наследование интерфейсов IManage и IDraw также присутствует.

В качестве отступления, интерес представляет тот факт, что в сгенерированном программном коде присутствует заготовка под деструктор класса.

~Class(){

}

В управляемых средах, таких как CLR, уничтожением объектов в памяти занимается сборщик мусора как только обнаруживает что объект вышел из зоны видимости и не имеет ссылок, его можно вызвать методом GC.Collect(), или вызвать метод Finalize() для объекта, но в любом случае решение об удалении будет принято на основе внутренних алгоритмов среды CLR. Деструктор в том виде нужен для неуправляемых объектов, удалять которые сборщик мусора не умеет. Если в дальнейшей работе такие объекты не планируется использовать, то данный фрагмент программного кода может быть удален.

Реализация метода Create добавленная на этапе проектирования также сохранилась. Данный программный код был добавлен в целях демонстрации возможностей SPARX Enterprise Architect.

public static IManage Create(){

if (start_instance == null && current_instance == null)

{

start_instance = new Class();

current_instance = start_instance;

return start_instance; //implicit upcast to IManage

}

else

{

//Design error -- must not be instantiated more than once

throw new Exception("Attemp to create second instance of ST");

}

}

Реализованы интерфейсы

public interface IDraw {

///

/// <param name="g"></param>

void Draw(Graphics g);

///

/// <param name="p"></param>

bool CheckClick(Point p);

///

/// <param name="p"></param>

void SetPos(Point p);

}//end IDraw

И перечисления

public enum Visability : int {

PRIVATE,

PUBLIC

}//end Visability

§ 2.5 Выводы

Таким образом, насколько это возможно в рамках данной работы, были рассмотрены ряд возможностей программного продукта SPARX Enterprise Architect для моделирования UML диаграмм и генерации кода.

Был создан «каркас» условного приложения из класса, интерфейсов, перечислений. Программная связанность и наполнение могут быть реализованы на последующих этапах разработки приложения.

Глава 3. Visual Studio Community Edition

К сожалению, в данный пакет более не входят ряд инструментов UML моделирования – например UML Model Explorer, а ряд возможностей доступны только в платной Enterprise версии[5]. Тем не менее доступных возможностей вполне достаточно для данного исследования.

В состав бесплатно распространяемого данного пакета программного обеспечения входит компонент «Конструктор классов», установку которого необходимо произвести в Visual Studio Installer как показано на рисунке 5.

Рисунок 5. Установка отдельных компонентов

Visual Studio 2019 Community Edition

Если в предыдущей главе был получен программный код на основе визуального моделирования, то далее мы рассмотрим также использование Конструктора классов для создания диаграммы классов по существующему программному коду. Создание диаграммы классов показано на рисунке 6.

Рисунок 6. Создание диаграммы классов в

Visual Studio 2019 Community Edition

В целом, приходится признать, что что возможности программного продукта Microsoft сильно уступают Sparx Enterprise Architect. По крайней мере в Community Edition набор возможностей значительно уступает таковому в ранее рассмотренном программном продукте.

На рисунке 7 показана панель с набором немногочисленных инструментов, представленных в распоряжение исследователя фирмой Майкрософт.

Рисунок 7. Панель элементов Конструктора классов Microsoft Visual Studio Community Edition

§ 3.1 Разработка в Дизайнере Классов

      1. Тем не менее воспользуемся предоставленными инструментами для создания основы условной информационной системы. Для целей данного исследования разработаем тикетинговую информационную систему с минимальным функциональным наполнением.
        1. Создадим класс TroubleTicket с конструктором и свойством Issued. Поле Issued будет иметь тип System.DateTime, конструктор будет присваивать этому полю дату и время в момент создания экземпляра класса.

Также, создадим класс TTContainer который, как ясно следует из названия, будет контейнером для объектов типа TroubleTicket. Для этого создадим поле tickets типа TroubleTicket[]. Семантика [] означает что тип является массивом, а управляемом языке C# массивы реализуют интерфейс IEnumerable, что позволяет легко использовать для них шаблоны итерации.

В завершении соединим два класса связью типа Ассоциация. Результат показан на рисунке 8.

Рисунок 8. Классы и Ассоциация в Конструкторе классов

Для класса TroubleTicket программой был создан программный «каркас», в который было добавлено функциональное наполнение – присвоение значение полю Issued, а также возврат значения и модификатор доступа.

public class TroubleTicket

{

public DateTime Issued

{

get { return Issued; }

private set { Issued = value; }

}

public TroubleTicket() { Issued = DateTime.Now; }

}

Класс TTContainer

public class TTContainer

{

public TroubleTicket[] tickets

{

get => default;

set { }

}

public TroubleTicket TroubleTicket

{

get => default;

set { } } }

Стоит обратить внимание что дизайнер классов не позволяет объявлять массив в качестве свойства при этом отражая это схематически, что можно считать недостатком. При попытке изменить тип свойства теряется схематическая ассоциация с классом, представляющим этот тип. Во фрагменте 2 показано то что можно создать в дизайнере классов, а во фрагменте 1 исправленный вариант. В данной работе, таким образом показан программный код, соответствующий схематическому изображению в Дизайнере Классов и продемонстрировано каким он должен быть. На рисунке 9 справа показано наследование класса TroubleTicket от условного класса Ticket.

Рисунок 9. Классы и Наследование в Конструкторе классов

В отличие от Ассоциации данный тип связи в рассматриваемом продукте не имеет вообще каких-либо настроек, впрочем, отражается в программном коде корректно: public class TroubleTicket : Ticket

На рисунке 10 поле Issued перенесено в базовый класс Ticket, добавлен конструктор в базовый класс. Также, добавлен делегат для обработки события OnCreated.

Рисунок 10. Классы и Наследование в Конструкторе классов

Вызывает удивление тот факт, что в класс возможно добавить события, но сущности соответствующей EventHandler в Панели элементов нет. Самое близкое по смыслу это Делегат, но он не совместим с EventHandler по уровню абстракции который обеспечивает защиту от доступа к делегату в вызываемом им программном коде. На диаграмму добавлен делегат лишь для демонстрации, в программный код для обеспечения связанности приходится добавлять нестандартные решения:

public Foo()

{

OnCreateHandler hand;

hand = (s, e) =>

{

//Обработчик события

};

TroubleTicket.OnCreated += (s, e) => hand(s, e);

}

Помимо возможности создавать классы и связанность между ними в Дизайнере Классов также имеется возможность построить диаграмму классов имеющегося проекта. Именно эта возможность будет рассмотрена в следующем параграфе.

§ 3.2 Представление проекта в Дизайнере Классов

Для достижения целей данной работы был разработан небольшой проект дизайнера классов, который подробно будет рассмотрен в следующей главе. На данный момент данный проект будет использован для исследования возможностей Дизайнера Классов по построению диаграммы классов уже созданного проекта. Проект носит условное название UML Modeller.

Как уже отмечалось ранее, проект носит исследовательский и учебный характер поэтому не претендует на полноценную функциональность. Тем не менее, демонстрирует объектно-ориентированный подход в объеме возможном для данной работы.

Переходя к рассмотрению построенной Дизайнером Классов диаграмме, стоит отметить что отображаемые классы, относящиеся к фреймворку .NET по понятным причинам рассмотрены не будут. Лишь частично будет рассмотрен класс MainForm поскольку он непосредственно реализует интерфейс спроектированного приложения. Классы Program, Resources и Settings таким образом исключаются из рассмотрения. На представленном ниже рисунке 11.

Рисунок 11. Классы и Наследование в Конструкторе классов

На рисунке 1 показана диаграмма классов, созданная автоматически на основе программного кода рассматриваемого проекта. Показательно отсутствие связей между элементами, даже тех, которые присутствуют в функционале Дизайнера Классов. Тем не менее, классы и интерфейсы показаны корректно.

В данной работе не удалось установить, если это вообще возможно сделать, каким образом в Конструкторе Классов связать интерфейс и реализующий этот интерфейс класс. В ранее рассматриваемом SPARX Enterprise Architect для этого можно было использовать связь типа Генерализация.

§ 3.3 Выводы

Рассмотрев, таким образом, доступные в Community версии инструменты визуального моделирования можно заключить что полноценными они не являются. Отказ компании Майкрософт от поддержки ряда инструментов доступных в более ранних версиях и вывод других возможностей в платную Enterprise версию не позволяют полноценно оценить данный функционал и тем более дать положительную оценку доступным возможностями.

Глава 4. Проектирование UML приложения

Чтобы проиллюстрировать объектно-ориентированного подход на практике было разработано простое приложение, позволяющее моделировать классы на UML. Сама по себе разработка и реализация такого приложения является важным моментом для понимания и дальнейшего использования данного подхода.

§ 4.1 Интерфейс приложения

В разработанном приложении интерфейс минимален – позволяет создавать и переименовывать классы, добавлять в них поля и методы, передвигать мышкой схематичное изображение класса по форме.

Рис. 12 Интерфейс приложение UML Modeller

Полностью программный код обработчиков событий формы и ее инициализации представлен в Листинге 1 Приложения данной работы. Стоит обратить внимание на тот факт, что функциональное наполнение интерфейса состоит лишь из взаимодействий между элементами формы. Это иллюстрирует инкапсуляцию в объекте MainForm лишь тех методов и данных, которые необходимы для его функционирования и отделенных, таким образом, от остальных объектов приложения.

Отрисовка схематических изображений классов производится на форме, однако непосредственная реализация вынесена в ClassElement (Листинг 3).

Стандартные элементы Windows Forms расположенные внизу служат для добавления и редактирования элементов диаграммы.

§ 4.2 Классы и интерфейсы

Используемые классы показаны на листингах 2-4 в приложении к данной работе. Класс ClassContainer (Листинг 2) инкапсулирует методы управления классами и регистрацию событий на форме через интерфейс IManageContainer. Для обновления изменений со стороны элементов содержащихся в контейнере используется реализуемый интерфейс IUpdatable. Также ClassConatainer через интерфейс IMoveable осуществляет взаимодействие с ClassElement, обеспечивающий «перетаскивание» элементов диаграммы.

ClassElement(Листинг 3) в свою очередь вляется контейнером для экземпляров класса Feature, реализует отрисовку классов через интерфейс IDraw, перетаскивание через эинтерфейс IMoveable а также управление членами класса через интерфейс IClassElementManage.

Наконец класс Feature (Листинг 4) содержит информацию о свойствах класса, реализует интерфейс IDraw для отрисовки свойств.

§ 4.3 Выводы

Исследованный, таким образом, метод объектно-ориентированного проектирования с использованием С# демонстрирует высокий уровень гибкости, простоты и возможностей.

Заключение

      1. В проведенном исследовании были рассмотрены два программных продукта, позволяющих применять объектно-ориентированный подход для моделирования, проектирования и разработки информационных систем или других программных продуктов. Были рассмотрены сильные стороны и недостатки, проведен анализ возможностей генерации программного кода и обратного проектирования.
        1. Было создано собственное приложение приложение с применением объектно-ориентированного программирования.
          1. Существенно расширена база знаний и умений в применительно к исследуемым вопросам.

Можно считать исследование завершенным в требуемом объеме.

Список использованной литературы

1. Фаулер М. UML Основы – Краткое руководство по стандартному языку объектного моделирования / М. Фаулер. – Санкт-Петербург: Символ-Плюс 2018. – 192 с.

2. Ларман К. Применение UML 2.0 и шаблонов проектирования. / К. Ларман. – Москва: Вильямс. 2013 – 736 с.

интернет ресурсы

1. Enterprise Architect 15 User Guide

URL: https://www.sparxsystems.com/enterprise_architect_user_guide/15.0/

2. Microsoft Developer Network

URL: https://msdn.microsoft.com/en-us/

3. Хранилище документации Майкрософт для пользователей, разработчиков и ИТ-специалистов.

URL: https://docs.microsoft.com/ru-ru/

3. THE UNIFIED MODELING LANGUAGE SPECIFICATION

URL: https://www.omg.org/spec/UML/2.4.1/Superstructure/PDF

Приложения

Приложение 1. Листинг MainForm.cs

using System;

using System.Windows.Forms;

namespace UML_Modeller

{

public partial class MainForm : Form

{

public MainForm()

{

InitializeComponent();

ClassContainer

.GetInstance()

.AddPaintEvents(this);

}

private void LoadComboBox()

{

ClassList.Items.Clear();

ClassList.Text = "";

ClassList.Items.AddRange(

ClassContainer

.GetInstance()

.GetElementsNames()

.ToArray());

}

private void AddClassBtn_Click(object sender, EventArgs e)

{

ClassContainer

.GetInstance()

.CreateElement(ClassEdit.Text);

LoadComboBox();

}

private void ClassList_SelectedIndexChanged(object sender, EventArgs e)

{

FeaturesList.Text = "";

FeaturesList.Items.Clear();

FeaturesList.Items.AddRange(ClassContainer.GetInstance()

.GetElementByName(ClassList.Text)

.GetFeaturesNames()

.ToArray());

}

private void AddFeatureBtn_Click(object sender, EventArgs e)

{

var elem = ClassContainer.GetInstance()

.GetElementByName(ClassList.Text);

elem.AddFeature(FeatureEdit.Text, elem.GetFeaturesCount());

}

private void RenameClassBtn_Click(object sender, EventArgs e)

{

ClassContainer.GetInstance()

.GetElementByName(ClassList.Text)

.SetName(ClassEdit.Text);

LoadComboBox();

}

}

}

Приложение 2. Листинг ClassContainer.cs

using System.Collections.Generic;

using System.Windows.Forms;

namespace UML_Modeller

{

interface IUpdatable

{

void Update();

}

interface IManageContainer

{

void AddPaintEvents(Control c);

IClassElementManage CreateElement(string name);

IClassElementManage GetElementByName(string name);

List<string> GetElementsNames();

}

class ClassContainer : IManageContainer, IUpdatable

{

private static ClassContainer instance;

private static Control m_control;

private ClassContainer()

{ }

private static List<ClassElement> elements;

public void Update()

{

m_control.Refresh();

}

public static IManageContainer GetInstance()

{

if (instance == null)

{

instance = new ClassContainer();

elements = new List<ClassElement>();

}

return instance;

}

public void AddPaintEvents(Control c)

{

m_control = c;

c.Paint += ControlPaint;

c.MouseDown += ControlMouseDown;

c.MouseUp += ControlMouseUp;

c.MouseMove += ControlMouseMove;

}

//Set Form to DoubleBuffered to avoid flickering

private void ControlMouseMove(object sender, MouseEventArgs e)

{

bool t = false;

foreach (IMoveable elem in elements)

{

if (!t) t = elem.SetPos(e.Location);

}

if (t) m_control.Refresh();

}

private void ControlMouseUp(object sender, MouseEventArgs e)

{

foreach (IMoveable elem in elements)

{

elem.Unhook();

}

}

private void ControlMouseDown(object sender, MouseEventArgs e)

{

foreach (IMoveable elem in elements)

{

elem.CheckClick(e.Location);

}

}

private void ControlPaint(object sender, PaintEventArgs e)

{

foreach (IDraw elem in elements)

{

elem.Draw(e.Graphics);

}

}

public IClassElementManage CreateElement(string name)

{

var ce = new ClassElement(name, this);

elements.Add(ce);

m_control.Refresh();

return ce;

}

public IClassElementManage GetElementByName(string name)

{

foreach (IClassElementManage elem in elements)

{

if (elem.GetName() == name) return elem;

}

return null;

}

public List<string> GetElementsNames()

{

List<string> l = new List<string>();

foreach (IClassElementManage elem in elements)

{

l.Add(elem.GetName());

}

return l;

}

}

}

Приложение 3. Листинг ClassElement.cs

using System;

using System.Collections.Generic;

using System.Linq;

using System.Drawing;

namespace UML_Modeller

{

interface IMoveable

{

void CheckClick(Point p);

void Unhook();

bool SetPos(Point p);

}

interface IDraw

{

void Draw(Graphics g);

}

interface IClassElementManage

{

IClassElementManage AddFeature(string fname, int order);

string GetName();

IClassElementManage SetName(string name);

List<string> GetFeaturesNames();

int GetFeaturesCount();

}

class ClassElement : IDraw, IMoveable, IClassElementManage

{

private string Name;

public Rectangle Space;

public Rectangle Title;

public Font TitleFont;

public Point TitleCenter;

public SizeF TitleSize;

public static Rectangle LastSpace;

private static IUpdatable Container;

public List<Feature> features;

private bool hooked;

public ClassElement(string n, IUpdatable container)

{

TitleFont = new Font("Courier New", 12.0F, FontStyle.Bold);

Container = container;

hooked = false;

features = new List<Feature>();

Name = n;

if (LastSpace.X == 0)

{

Space = new Rectangle(20, 20, 0, 0);

LastSpace = Space;

return;

}

else

{

Space = new Rectangle(LastSpace.X + 20,

LastSpace.Y + 20, 0, 0);

LastSpace = Space;

}

}

public IClassElementManage AddFeature(string fname, int order)

{

var f = new Feature(fname, this, order);

features.Add(f);

Container.Update();

return this;

}

public List<string> GetFeaturesNames()

{

List<string> l = new List<string>();

foreach (Feature f in features)

{

l.Add(f.GetName());

}

return l;

}

public int GetFeaturesCount()

{

return features.Count();

}

public string GetName()

{

return Name;

}

public IClassElementManage SetName(string name)

{

Name = name;

Container.Update();

return this;

}

private bool mds;

private Point movediff;

public bool SetPos(Point p)

{

if (!mds && hooked)

{

movediff.X = p.X - Space.X;

movediff.Y = p.Y - Space.Y;

mds = true;

}

if (!hooked) return false;

Space.X = p.X - movediff.X;

Space.Y = p.Y - movediff.Y;

return true;

}

public void Unhook()

{

hooked = false;

mds = false;

}

public void CheckClick(Point p)

{

if (Title.Contains(p)) hooked = true;

}

private Size FeaturesSize;

private void CalculateFeaturesSize(Graphics g)

{

SizeF tmp = new SizeF(0,0);

foreach (Feature f in features)

{

SizeF t = f.GetSize(g);

if (tmp.Width < t.Width) tmp.Width = t.Width;

tmp.Height += t.Height;

}

FeaturesSize.Width = (int) tmp.Width+20;

FeaturesSize.Height = (int) tmp.Height+20;

}

private void CalculateTitleSize(Graphics g)

{

TitleSize = g.MeasureString(Name, TitleFont);

Title.X = Space.X;

Title.Y = Space.Y;

Title.Height = (int)TitleSize.Height + 20;

Title.Width = (int)TitleSize.Width +20;

}

private void RecalcSpace()

{

if (FeaturesSize.Width < Title.Width) Space.Width = Title.Width;

else

{

Space.Width = FeaturesSize.Width;

Title.Width = Space.Width;

}

Space.Height = Title.Height + FeaturesSize.Height;

}

public void CalculateTitleCenter()

{

TitleCenter.Y = Title.Y + 10;

TitleCenter.X = Space.X + (Math.Abs((int)Space.Width

- (int)TitleSize.Width)) / 2;

}

public void Draw(Graphics g)

{

CalculateFeaturesSize(g);

CalculateTitleSize(g);

RecalcSpace();

CalculateTitleCenter();

g.FillRectangle(Brushes.LightGray, Space);

g.DrawRectangle(Pens.Black, Title);

g.DrawRectangle(Pens.Black, Space);

g.DrawString(Name, TitleFont, Brushes.Black, TitleCenter);

foreach (IDraw elem in features)

{

elem.Draw(g);

}

}

}

}

Приложение 4. Листинг Feature.cs

using System;

using System.Drawing;

namespace UML_Modeller

{

class Feature : IDraw

{

ClassElement Parent;

string Name;

Font FeatureFont;

int m_order;

int NameWidth;

int NameHeight;

public Feature(String name, ClassElement parent, int order)

{

Parent = parent;

Name = name;

m_order = order;

}

public SizeF GetSize(Graphics g)

{

FeatureFont = new Font("Courier New", 12.0F,

FontStyle.Regular);

SizeF s = g.MeasureString(Name, FeatureFont);

NameWidth = (int)s.Width;

NameHeight = (int)s.Height;

return s;

}

public string GetName()

{

return Name;

}

public void Draw(Graphics g)

{

g.DrawString(Name, FeatureFont, Brushes.Black,

Parent.Title.X + 10,

Parent.Title.Y + Parent.Title.Height + 5 +

m_order * NameHeight);

}

}

}

  1. Ларман К. Применение UML 2.0 и шаблонов проектирования. Практическое руководство. М:2013 с.38

  2. Фаулер М. UML Основы СПб:2018 с.61

  3. Мартин Фаулер. UML Основы с.94

  4. UML Superstructure Specification, v2.1.1, p.69

  5. https://docs.microsoft.com/ru-ru/visualstudio/modeling/what-s-new-for-design-in-visual-studio?view=vs-2017&viewFallbackFrom=vs-2019