Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
attachment_1.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
397.82 Кб
Скачать

14. Компоненты: объекты, субъекты, аспекты.

Еще один смутный вопрос (его не было в лекциях).

Объектом в языке С++ называется экземпляр класса. Объект любого ООП обладает состоянием, поведением и идентичностью. На примере классов состояние – это поле класса, поведение – его методы, а идентичность – название.

Субъектом ООП называется непосредственно сам программист, человек, читающий или использующий эту программу, в общем, любой субъект (в общепринятом смысле этого слова), так или иначе имеющий отношение к программе или ее использованию.

Аспекты – принципы выделения объектов. Основные аспекты таковы: 1) если мы считаем “нечто” отдельным понятием, делаем это “нечто” классом. 2) если мы считаем что-то объектом, делаем его классом. 3) если два класса имеют одинаковые методы, объединяем их и делаем базовый класс.

15. Подходы к декомпозиции программ и накоплению компонент программ

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

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

Существует широкий спектр методов декомпозиции задачи. На следующем рисунке представлена классификация таких методов.

К ак видно из рисунка, существует три основных варианта декомпозиции: простая декомпозиция (trival), функциональная (functional) идекомпозиция данных. Вопрос об использовании того или иного типа декомпозици при написании параллельной программы решается исходя из структуры самой задачи. Причем, в зависимости от условий, можно использовать сразу несколько типов.

Тривиальная декомпозиция

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

Функциональная декомпозиция

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

Предположим наша задача сводится к применению некоего функционального оператора к большому массиву данных: S[i]=F(a[i]). Предположим также, что выполнение функции F над одним элементом массива занимает достаточно большое время и нам хотелось бы это время сократить. В этом случае мы можем попытаться представить исходную функцию как композицию нескольких фунуций: S(a[i])=I(H(R(a[i]). Произведя декомпозицию мы получим систему последовательных задач:

x =r(a[i]); y=h(x); b[i]=i(y);

Каждая из этих задач может быть выполнена на отдельном узле кластера. Как можно заметить общее время обработки одного элемента массива a[i] в результате не изменяется, а скорее немного увеличивается за счет межпроцессорных пересылок. Однако общее время обработки всего массива заметно снижается за счет того, что в нашем примере одновременно идет обработка сразу трех элементов массива.

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

Первая особенность сосотоит в том, что выход кластера на максимальную эффективность происходит не сразу после запуска задачи, а постепенно, по мере того, как происходит частичная обработка первого элемента массива. Второй и третий процессоры в нашем примере, которые отвечают за выполнение функций g(x) и f(y), будут простаивать до тех пор, пока не закончится выполнение функции h(a[1]) на первом процессоре. Третий процессор будет простаивать до окончания выполнения функции g(a[1]). По аналогичному сценарию, только в зеркальном отображении, происходит окончание работы.

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

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

Декомпозиция данных

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

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

Объектно-ориентированное проектирование состоит в описании структуры и поведения проектируемой системы, то есть, фактически, в ответе на два основных вопроса:

  • Из каких частей состоит система.

  • В чём состоит ответственность каждой из частей.

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

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

Большое значение имеет правильное построение иерархии классов. Одна из известных проблем больших систем, построенных по ООП-технологии — так называемая проблема хрупкости базового класса. Она состоит в том, что на поздних этапах разработки, когда иерархия классов построена и на её основе разработано большое количество кода, оказывается трудно или даже невозможно внести какие-либо изменения в код базовых классов иерархии (от которых порождены все или многие работающие в системе классы). Даже если вносимые изменения не затронут интерфейс базового класса, изменение его поведения может непредсказуемым образом отразиться на классах-потомках. В случае крупной системы разработчик базового класса не просто не в состоянии предугадать последствия изменений, он даже не знает о том, как именно базовый класс используется и от каких особенностей его поведения зависит корректность работы классов-потомков.

В разработке программного обеспечениякомпоновщик (также реда́ктор свя́зейлинкер — от англ. link editor, linker) — программа, которая производит компоновку: принимает на вход один или несколько объектных модулей и собирает по ним исполнимый модуль.

Для связывания модулей компоновщик использует таблицы имён, созданные компилятором в каждом из объектных модулей. Такие имена могут быть двух типов:

  • Определённые или экспортируемые имена — функции и переменные, определённые в данном модуле и предоставляемые для использования другим модулям

  • Неопределённые или импортируемые имена — функции и переменные, на которые ссылается модуль, но не определяет их внутри себя

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

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

Простые компоненты могут быть заданы непосредственно, а сложные обычно строятся пошаговым образом. Процесс уточнения, улучшения или расширения компонентов в XP называют "рефакторинг". Начиная с некоторого первичного текста программного компонента, пошаговым образом формируется его новое частичное определение, которое в каком-то отношении лучше, чем предыдущее. Оно может полнее, точнее или эффективнее решать задачу, может стать более удобочитаемым, лучше приспособленным к отладке или сопровождению и т.д, и т.п.

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]