Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Пример построения диаграммы классов.




Задание: Построить диаграмму классов DOM демонстрационно-обучающей системы решения квадратных уравнений.

Шаг 1. «Вначале было слово…»

Квадратное уравнение имеет вид ax2+bx+c=0. Очевидно, что на данном этапе имеем один класс «квадратное уравнение». Используя русско-английский словарь и нотацию Borland, назовем его TQuadraticEquation. Полями (данными) класса будут коэффициенты уравнения, методами (функциями) – функция вычисления корней.

Таблица 1

Класс Атрибуты/методы Описание
TQuadraticEquation double a Коэффициент уравнения a
double b Коэффициент уравнения b
double c Коэффициент уравнения c
int Roots(double* x1, double* x2) Функция вычисления корней. Входные параметры: x1 – адрес переменной для записи значения х1; х2 – адрес переменной для записи значения х2. Возвращаемое значение: Количество корней уравнения (0, 1 или 2)

 

 

Рис 1. Диаграмма классов на первом шаге.

Шаг 1.1.

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

Таблица 1.1

Класс Атрибуты/методы Описание
TQuadraticEquation
double D() Функция вычисления D
int RootCount() Функция, возвращающая количество корней уравнения (0, 1 или 2)
double x1() Функция вычисления корня x1
double x2() Функция вычисления корня x2
double y(double x) Функция y(x)
bool vertex(double* x, double *y) Функция вычисления направления ветвей и точки вершины параболы. Входные параметры: x – адрес переменной для записи значения координаты х точки вершины параболы; y – адрес переменной для записи значения координаты у точки вершины параболы. Возвращаемое значение: Направление ветвей вверх (true) или вниз (false)

Оценка модели:

Очевидно, что данная модель не соответствует принципам high cohesion (сильного сцепления) и единственности ответственности, поскольку класс несет как функционал описания квадратного уравнения, так и функционал для его решения и для построения графика. Класс перегружен методами, что затрудняет понимание и сопровождение. А при изменении алгоритма решения или добавления нового алгоритма (например, теоремы Виета), класс необходимо будет дополнить (как? еще дополнить?!) новыми методами, что является нарушением принципа открытости/закрытости.

Рис 1.1. Окончательная диаграмма классов на первом шаге.

Вывод:

Необходимо разделить «зоны ответственности» между различными классами. Кроме того, неплохо было бы дополнить классы конструкторами и деструкторами.

Шаг 2. «Раз ромашка, два ромашка…»

Выделим зоны функциональности и разделим их между соответствующими классами (и да поможет нам электронный словарь ABBY Lingvo 12):

· Описание квадратного уравнения (класс TQuadraticEquation);

· Алгоритм решения квадратного уравнения (класс TQuadraticSolution);

· Получение данных для постройки графика (класс TQuadraticGraphData).

Класс TQuadraticEquation будет связан («ассоциирован») с классом TQuadraticSolution и с классом TQuadraticGraphData (Очевидно, что решить уравнение без самого уравнения или построить график функции без функции нельзя.). Классы TQuadraticSolution и TQuadraticGraphData на данном этапе между собой не связаны (решение и построение графика не зависят друг от друга). Считая само уравнение частью процесса решения и построения, получим:

· TQuadraticSolution агрегирует TQuadraticEquation. Поскольку уравнение может иметь много способов решения, а «решение» может в один конкретный момент может решать только одно уравнение, то кратность связи будет «один» со стороны класса TQuadraticEquation и «много» со стороны класса TQuadraticSolution.

· TQuadraticGraphData агрегирует TQuadraticEquation. Кратность см. пункт выше.

Таблица 2

Класс Атрибуты/методы Описание
TQuadraticEquation
TQuadraticEquation() Конструктор умолчания
TQuadraticEquation(double a, double b, double c) Параметрический конструктор Входные параметры: Коэффициенты a, b, c квадратного уравнения
~ TQuadraticEquation() Деструктор
TQuadraticSolution TQuadraticEquation* Equation Указатель на решаемое уравнение
TQuadraticSolution() Конструктор умолчания
TQuadraticSolution( TQuadraticEquation* E) Параметрический конструктор Входные параметры: E – указатель на решаемое уравнение
~TQuadraticSolution() Деструктор
TQuadraticGraphData TQuadraticEquation* Equation Указатель на уравнение
TQuadraticGraphData() Конструктор умолчания
TQuadraticGraphData( TQuadraticEquation* E) Параметрический конструктор Входные параметры: E – указатель на уравнение для графика
~TQuadraticGraphData() Деструктор

Примечания:

1. Класс TQuadraticSolution на диаграмме не имеет поля TQuadraticEquation* Equation. Это поле указано на самой связи агрегации. CASE-средства, такие как StarUML, автоматически добавляют это поле в код класса для реализации механизма связи при автоматической генерации кода. На изображении класса TQuadraticGraphData это поле добавлено вручную в секции атрибутов. При этом на самой связи оно не указано. Допускается использовать любой из вариантов.

2. Конструкторы выделены с помощью стереотипа «create», а деструкторы – «destroy». Это позволяет избежать добавления возвращаемого типа void для этих методов и не использовать для деструктора символ ~ (поскольку на диаграмме классов UML этот символ тоже используется).

Рис 2. Диаграмма классов на втором шаге.

Оценка модели:

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

Следующий насущный вопрос: кто (или что) будет «связывать» уравнение с решением и с построением графика, а так же «следить» за ходом этих процессов? Перефразируя «умным языком», какой класс (объект) будет отвечать за обработку системных событий?

Вывод:

Необходимо включить в модель контроллер.

Справка:

Контроллер – структурный паттерн проектирования GRASP (англ. General Responsibility Assignment Software Patterns (общие образцы распределения обязанностей)) – это объект, который отвечает за обработку системных событий и не относится к интерфейсу пользователя. Контроллер определяет методы для выполнения системных операций.

Шаг 3. «Позовите Вия!..»

Итак, в системе для модуля-демонстратора определен прецедент «решить уравнение» (см. диаграмму прецедентов), состоящий из следующих сервисов:

· Ввести коэффициенты

· Вычислить корни

· Построить график

Очевидно, что прежде, чем ввести коэффициенты, объект «уравнение» необходимо создать (строго говоря, за создание экземпляров классов в GRASP отвечает другой паттерн – Creator, но для упрощения примера прикроем глаза на эту деталь). То же касается и экземпляров других классов. Список методов класса контроллера (назовем его, по традиции, TQuadraticController) будет примерно такой:

 

Таблица 3

Метод Описание
TQuadraticEquation* CreateEquation() Создает экземпляр класса «квадратное уравнение» и возвращает ссылку на созданный объект.
TQuadraticSolution* CreateSoluion() Создает экземпляр класса «решение квадратного уравнения» и возвращает ссылку на созданный объект. (Т.к. в системе есть решение только одного типа, то метод для внутреннего использования функцией Solve)
TQuadraticGraphData* CreateGraphData () Создает экземпляр класса «данные для построения графика квадратного уравнения» и возвращает ссылку на созданный объект. (Т.к. в системе есть только один тип графика, то метод для внутреннего использования функцией Draw)
void Solve(TQuadraticEquation* E, TStrings* S) Функция демонстрации решения уравнения. Входные параметры: Е – указатель на решаемое уравнение S – указатель на коллекцию строк, в которую будет помещен ход решения (стандартный класс для хранения массива строк Borland C++ Builder)
void Draw(TQuadraticEquation* E, TCanvas* C) Функция построения графика. Входные параметры: Е – указатель на решаемое уравнение C – ссылка на объект типа «холст», где будет нарисован график (стандартный класс для отображения граф. информации Borland C++ Builder)

 

Для экономии места и времени первая колонка с наименованием классов опущена.

Рис. 3. Диаграмма классов на третьем шаге.

Примечания:

1. Стереотип «controller» на изображении класса является ни к чему не обязывающим словом, указывающим лишь на то, что класс играет роль контроллера. Обозначение предназначено для более полного понимания учащимися назначения экземпляров класса в системе. StarUML игнорирует этот стереотип, генерируя каркас кода как для обычного класса.

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

3. Класс «контроллер» связан с остальными ассоциациями без указания типа, что ничего не говорит об особенностях реализации данных связей. Это обозначение применено здесь для упрощения вида диаграммы.

Оценка модели:

На данном этапе развития системы модель с достаточной полнотой удовлетворяет принципам проектирования архитектуры. Каждый класс имеет достаточное сцепление (на текущем уровне знаний учащихся).

Принцип единственности ответственности также выполняется (почти, не считая контроллера, но такова его судьба).

Принцип минимального знания (закон Деметера) выполняется (на первый взгляд, ибо конкретной реализации нет, и проверить не на чем).

Принцип DRY выполняется – ни один класс не повторяет функциональности другого.

Принцип открытости/закрытости выполняется: для создания нового типа уравнения или нового алгоритма решения не нужно модифицировать существующие классы (кроме контроллера, но об этом ниже), а можно создать новые.

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

Вывод:

Есть о чем подумать и куда развиваться. Скорее всего, понадобиться еще один шаг для унификации интерфейсов (обобщения имеющихся понятий). Но это в следующем номере.

Заключение

В данном примере рассмотрена только модель одной части системы, а именно – модуля для демонстрации решения квадратных уравнений. Каждая следующая подсистема будет добавлять в модель свои классы. Например, подсистема контроля знаний может оперировать такими понятиями: «генератор коэффициентов уравнения» (создает коэффициенты для различного количества корней), «коллекция данных пользователя» (содержит результаты пользовательских вычислений), «проверяющий решения», «выставляющий оценку», «пользователь», «оценка» и т.п. Кроме того, в этой подсистеме появляется слой ORM, так как данные о пользователе хранятся в БД. В зависимости от выбранного типового (или не типового) решения реализации DOM, могут быть использованы классы «транзакция», «mapper», «dataset» и т.п.

 


Поделиться:

Дата добавления: 2015-08-05; просмотров: 362; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.006 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты