ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 06.11.2023
Просмотров: 923
Скачиваний: 6
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
271 связность и сцепление модулей: s
A
= 0,5; s
B
= 0,7; s
C
= 0,3; s
D
= 0,9; s
E
=
1,0; c
AB
= 0,5; c
AC
= 0,7; c
CB
= 0,3; c
CD
= 0,1; c
DE
= 0.3.
Вычисляем элементы матрицы первого порядка, которые соответст- вуют вероятностям дуг графа: d
AB
= 0,15 * (0,5 + 0,7) + 0,7 * 0,5 = 0,53; d
AC
= 0,15 * (0,5 + 0,3) + 0,7 * 0,7 = 0,61; d
CB
= 0,15 * (0,3 + 0,7) + 0,7 * 0,3 = 0,36; d
CD
= 0,15 * (0,3 + 0,9) + 0,7 * 0,1 = 0,25; d
DE
= 0,15 * (0,9 + 1,0) + 0,7 * 0,3 = 0,495.
По полученным данным можно построить матрицу первого порядка
(рис. 6.5). Переходим к построению полной матрицы зависимостей. Для этого (в нашем простом примере визуально) определяем все пути для каждой пары модулей:
1.
Пара A, B: путь A – B и путь A – C – B.
2.
Пара A, C: путь A – C и путь A – B – C.
3.
Пара A, D: путь A – C – D и путь A – B – C – D.
4.
Пара A, E: путь A – C – D – E и путь A – B – C – D – E.
5.
Пара B, C: путь B – C и путь B – A – C.
6.
Пара B, D: путь B – C – D и путь B – A – C – D.
7.
Пара B, E: путь B – C – D – E и путь B – A – C – D – E.
8.
Пара D, C: путь C – D.
9.
Пара D, E: путь D – E.
10. Пара E, C: путь E – D – C.
Рис. 6.5. Матрица зависимостей модулей первого порядка
Вычисляем значения вероятностей для найденных путей, используя значения вероятностей дуг графа:
1.
P
AB
= d
AB
= 0,53; P
ACB
= d
AC
* d
CB
= 0,61 * 0,36 = 0,22.
2.
P
AC
= d
AC
= 0,61; P
ABC
= d
AB
* d
BC
= 0,53 * 0,36 = 0,19.
3.
P
ACD
= d
CA
* d
CD
= 0,61 * 0,25 = 0,15; P
ABCD
= d
AB
* d
BC
* d
CD
=
0,53 * 0,36 * 0,25 = 0,05.
4.
P
ACDE
= d
AC
* d
CD
* d
DE
= 0,61 * 0,25 * 0,495 = 0,15; P
ABCDE
= d
AB
* d
BC
* d
CD
* d
DE
= 0,53 * 0,36 * 0,25 * 0,495 = 0,02.
5.
P
BC
= d
BC
= 0,36; P
BAC
= d
BA
* d
AC
= 0,53 * 0,61 = 0,32.
6.
P
BCD
= d
BC
* d
CD
= 0,36 * 0,25 = 0,09; P
BACD
= d
BA
* d
AC
* d
CD
=
0,53 * 0,61 * 0,25 = 0,08.
7.
P
BCDE
= d
BC
* d
CD
* d
DE
= 0,36 * 0,25 * 0,495 = 0,044; P
BACDE
= d
BA
* d
AC
* d
CD
* d
DE
= 0,53 * 0,61 * 0,25 * 0, 495 = 0,04.
272 8.
P
CD
= d
CD
= 0,25.
9.
P
DE
= d
DE
= 0,495.
10. P
EDC
= d
ED
* d
DC
= 0,495 * 0,25 = 0,12.
Теперь, используя найденные вероятности путей с учетом того, что пути между парой модулей не являются взаимоисключающими, опреде- лим зависимости между модулями.
1.
Пара A, B. Здесь возможны два пути, поэтому d
1
AB
= P
AB
+ P
ACB
- P
AB
+ P
ACB
=
= 0,53 + 0,22 – 0,53 * 0,22 = 0,63.
2.
Пара A, C. Здесь также имеется два пути, поэтому d
1
AC
= P
ABC
+
P
ACB
- P
ABC
+ P
AC
= 0,19 + 0,61 – 0,19 * 0,61 = 0,68.
3.
Пара A, D. Имеет два пути для возможных изменений. Зависи- мость между этими модулями определяется значением d
1
AD
= P
ACD
+
P
ABCD
- P
ACD
* P
ABCD
= 0,15 + 0,05 – 0,15 * 0,05 = 0,19.
4.
Пара A, E. Также имеется два пути, следовательно, d
1
AE
= P
ACDE
+ P
ABCDE
- P
ACDE
* P
ABCDE
= 0,15 + 0,02 – 0,15 * 0,02 = 0,17.
5.
Пара B, C. Для возможных изменений имеется два пути, поэто- му d
1
BC
= P
BC
+ P
BAC
- P
BC
* P
BAC
= 0,36 + 0,32 – 0,36 * 0,32 = 0,56.
6.
Пара B, D. Также имеется два пути, d
1
BD
= P
BCD
+ P
BACD
- P
BCD
*
P
BACD
= 0,09 + 0,08 – 0,09 * 0,08 = 0,16.
7.
Пара B, E. Имеет два пути, d
1
BE
= P
BCDE
+ P
BACDE
- P
BCDE
* P
BACDE
= 0,044 + 0,04 – 0,044 * 0.04 = 0,08.
8.
Пара C, D. Здесь только один путь, следовательно, d
1
CD
= P
CD
= d
CD
= 0,25.
9.
Пара D, E. Тоже только один путь, d
1
DE
= P
DE
= d
DE
= 0,495.
10. Пара E, C. Здесь только один путь, d
1
EC
= P
EDC
= d
ED
* d
DC
=
0,495 * 0,25 = 0,12.
После всех этих расчетов можно построить полную матрицу зависи- мостей между модулями системы (рис. 6.6).
Рис. 6.6. Полная матрица зависимостей модулей
По полученной матрице можно определить, например, что при изме- нении модуля A, вероятность того, что изменится модуль E, равна 0,17.
Суммируя элементы любой строки (за исключением диагонального
273 элемента) можно вычислить число модулей, которые должны быть из- менены при изменении соответствующего модуля программы. Напри- мер, если изменится модуль C, ожидаемое число изменений равно 1,61.
Исключив диагональ, вычитая каждый элемент строки из 1,0 и пере- множая результаты, получим вероятность того, что изменение модуля не повлечет за собой изменения других модулей. Например, для модуля
C эта вероятность равна
P = (1 – 0,68) (1 – 0,56) (1 – 0,25) (1 – 0,12) = 0.09.
Суммируя все элементы матрицы, и деля сумму на число модулей, можно получить грубую оценку сложности программной системы (диа- гональные и повторяющиеся элементы не учитываются). В нашем при- мере получим значение сложности, равное 0,49. Чем выше это значение, тем сложнее система.
В заключение следует заметить, что несмотря на привлекательность рассмотренной модели с учетом того факта, что она основана на ключе- вых свойствах структуры программы, все же модель основывается на многих недостаточно выверенных предположениях.
1 ... 20 21 22 23 24 25 26 27 ... 37
6.4. Представление архитектуры программных систем
6.4.1. Модульно-интерфейсный подход
В общем случае модульная программная система представляет собой древовидную структуру, в узлах которой размещаются программные модули, а направленные дуги показывают статическую подчиненность модулей. Если в тексте модуля имеется ссылка на другой модуль, то их на структурной схеме соединяет дуга, которая исходит из первого мо- дуля и входит во второй модуль. При этом модульная структура про- граммной системы, кроме структурной схемы, должна включать в себя совокупность спецификаций модулей, образующих эту систему.
Функции верхнего уровня обеспечиваются главным модулем. Он управляет выполнением нижестоящих функций, которым соответству- ют подчиненные модули. При определении набора модулей, реализую- щих функции конкретного алгоритма, необходимо учитывать следую- щее:
1) модуль вызывается на выполнение вышестоящим по иерархии моду- лем и, закончив работу, возвращает ему управление;
2) принятие основных решений в алгоритме выносится на максимально высокий по иерархии уровень;
3) если в разных местах алгоритма используется одна и та же функция, то она оформляется в отдельный модуль, который будет вызываться по мере необходимости.
Структурное проектирование обычно подразумевает использование структур для разделения различных частей системы. Каждая часть при этом может проектироваться отдельно. Один из наиболее традиционных методов проектирования операционных систем в 70-е годы 20 века со-
274 стоял в том, что проект каждого основного модуля системы выполнялся отдельно. Этот подход называется модульно-интерфейсным.
Анализируя существующие системы, можно заключить [35, 41], что операционная система состоит из системы ввода-вывода, планировщика времени процессора, менеджера памяти, системы управления файлами и т. д. Каждый модуль выделяется и описывается, кроме того, определя- ется его интерфейс с другими модулями. Модули и их взаимные связи образуют абстракцию системы высокого уровня. После этого этапа для дальнейшего проектирования и реализации модули рассматриваются по отдельности.
Такая же процедура может быть повторена в отношении какого-либо одного модуля системы, и последующую работу над модулем можно расчленить на индивидуальные задания по программированию. После того как все эти модули спроектированы и реализованы, они связыва- ются воедино в соответствии с заранее определенными интерфейсами.
Соблюдение правильного интерфейса представляет собой серьезную проблему в модульно-интерфейсном подходе. Модули и их интерфейсы описываются весьма неформально и неточно. Поэтому, хотя отдельные модули и пишутся в соответствии с заданными спецификациями, часто оказывается, что в них заложено неверное представление об операцион- ном окружении. И когда модули связываются вместе, они не взаимодей- ствуют должным образом. После того, как модули получены в коде компьютера, разрешение возникших конфликтов может оказаться чрез- вычайно трудным делом.
В принципе, если интерфейс полностью специфицирован, то в этом отношении не должно возникать трудностей. К сожалению, однако, первоначальный общий проект и планирование редко доводят до такого уровня детализации, когда используется язык программирования. В ре- зультате важные решения, которые должны были быть приняты опыт- ными разработчиками в начале работы над проектом, отодвигаются внутрь модулей. В конечном счете, программисты принимают решения, имеющие глобальные последствия, базируясь на очень ограниченной и узкой точке зрения на систему. Решения могут приниматься и чрезвы- чайно квалифицированными людьми, но не в тот момент, когда нужно.
Правильное определение и выделение модулей представляет собой трудную задачу (заметим, что при объектно-ориентированном проекти- ровании возникает не менее сложная задача определения и выделения классов). Тесно связанные между собой части системы должны входить в один и тот же модуль. Было предложено считать мерой связности двух частей системы число предположений, которое одна часть должна де- лать относительно другой части. Слишком много или слишком мало информации об окружении, в котором работают соседние модули, мо- жет иметь плохие последствия при проектировании модуля.
Рассмотрим, например, модуль A, работающий со структурой дан- ных. Соседний модуль B должен знать точный протокол для связи с модулем A. Однако он не должен знать всех подробностей о локальной структуре данных модуля A. При проектировании одного модуля не-
275 формальное использование информации о внутренних спецификациях других модулей может оказаться вредным. Так, пусть в предыдущем примере модуль B использует информацию о локальной структуре дан- ных модуля A. В этом случае, если модулю A потребуется изменить свою организацию, модификация модуля B может оказаться неприят- ным делом. Неверное представление модуля B о структуре данных мо- дуля A может не проявиться до тех пор, пока вся система не выйдет из строя.
Модульно-интерфейсный подход – один из методов структурного проектирования. Спецификации модулей и их интерфейсов дают струк- турную основу для проектирования каждого модуля и системы в целом.
Спецификация программного модуля состоит из функциональной специ-
фикации, описывающей семантику функций, выполняемых этим моду- лем по каждому из его входов, и синтаксической спецификации его вхо-
дов, позволяющей построить на используемом языке программирования синтаксически правильное обращение к модулю [33].
Существуют различные методы разработки модульной структуры программной системы, в зависимости от которых определяется порядок разработки структуры системы, программирования и отладки модулей, указанных в этой структуре. Обычно в литературе выделяют два основ- ных метода [10, 17, 30, 37, 40]: метод нисходящей разработки (метод
“сверху-вниз” или top-down) и метод восходящей разработки (метод
“снизу-вверх” или bottom –up).
По мнению В. Турского [37], формулировка аналитический и синте- тический подходы к проектированию программ является более пра- вильной, поскольку действительная суть проблемы не столько в выборе направления при проектировании, сколько в определении того, что именно преобладает: факторизация (аналитические шаги) или компо-
зиция (синтетические шаги). Ни один из этих подходов в их чистом виде не является жизнеспособной методологией проектирования: чисто аналитическое проектирование сравнимо с построением “пирамиды с плавающей в воздухе вершиной”, а чисто синтетическое – с построени- ем пирамиды ”стоящей на голове”. Реальная стратегия проектирования почти всегда представляет собой разумное сочетание этих двух подхо- дов.
6.4.2. Объектно-ориентированный поход
Как отмечает Киммел П. [16], существует две методики разработки объектно-ориентированных программных систем, которые он условно называет “потребление” и “производство". Команды разработчиков могут работать совместно, используя либо одну из методик, либо обе.
Но если руководитель проекта не уверен и не знает, хватит ли квалифи- кации его сотрудников для того, чтобы использовать чужие объекты, или способны ли они разрабатывать собственные, то это может привес- ти к серьезным проблемам.
276
Первая методика заключается в том, что команда разработчиков ак- тивно использует библиотеки и классы, разработанные другими. При такой методике разработчики понимают, что их опыт и квалификация пока недостаточны для разработки серьезных объектов. Вторая методи- ка применяется тогда, когда команда хорошо осведомлена о процессе разработки шаблонов, рефакторинге и имеет удачный опыт разработки объектно-ориентированных проектов, включая разработку собственных классов. Обе техники приемлемы для использования, но важно знать, какая из них дает большие шансы добиться успеха.
Выявление классов, правильно описывающих предметную область проекта, является самой сложной задачей, которую предстоит решить разработчику. Выявление нужных классов намного сложнее процесса создания диаграмм. Если команда разработчиков не смогла определить классы, точно описывающие задачу, то неважно, сколько средств будет потрачено на средства разработки, в конечном счете есть большая веро- ятность того, что созданные модели окажутся неработоспособными.
Не каждый класс является классом предметной области. Массивы, наборы и классы графического интерфейса не являются классами пред- метной области. Классы предметной области – это сущности, описы- вающие задачу предметной области, например, такие классы, как сту- дент, преподаватель, регистрация, экзамены в приложении, хранящем информацию о поступающих в вуз, или такие классы, как заказы, люди, уголовные дела, счета, денежные вклады и др. Каждому классу пред- метной области соответствует объект предметной области [8, 23, 31].
Объект – это сущность, которая используется при выполнении неко- торой функции или операции (преобразования, обработки, формирова- ния и т.д.). Объекты могут иметь динамическую или статическую при- роду: динамические объекты используются в одном цикле воспроизвод- ства, например заказы на продукцию, счета на оплату, платежи; стати- ческие объекты используются во многих циклах воспроизводства, на- пример, оборудование, персонал, запасы материалов. На концептуаль- ном уровне построения модели предметной области уточняется состав классов объектов, определяются их атрибуты и взаимосвязи. Таким об- разом строится обобщенное представление структуры предметной об- ласти.
Многие учебники по объектно-ориентированному программирова- нию рекомендуют поиск в предметной области существительных, а за- тем – привязку к ним глаголов. Существительные впоследствии перехо- дят в классы, а глаголы – в методы [10, 15]. Это самый легкий способ, но он дает только 20% всех классов, которые реально потребуется вы- явить. Если затем на этапе анализа обнаружились только классы и мето- ды, выявленные сочетанием существительных и глаголов, то, вероятнее всего, в разработанных моделях будет наблюдаться нехватка классов и потребуется дополнительный углубленный анализ. Тем не менее, выяв- ление существительных и глаголов предметной области является хоро- шим началом.