Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем


Скачать 1.25 Mb.
Название Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем
страница 4/10
Тип Руководство пользователя
rykovodstvo.ru > Руководство эксплуатация > Руководство пользователя
1   2   3   4   5   6   7   8   9   10

Архитектура


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

Архитектура - это совокупность существенных решений касательно:

  • организации программной системы;

  • выбора структурных элементов, составляющих систему, и их интерфейсов;

  • поведения этих элементов, специфицированного в кооперациях с другими элементами;

  • составления из этих структурных и поведенческих элементов все более и более крупных подсистем;

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

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

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



Рис. 2.20 Моделирование системной архитектуры

Вид с точки зрения прецедентов (Use case view) охватывает прецеденты, которые описывают поведение системы, наблюдаемое конечными пользователями, аналитиками и тестировщиками. Этот вид специфицирует не истинную организацию программной системы, а те движущие силы, от которых зависит формирование системной архитектуры. В языке UML статические аспекты этого вида передаются диаграммами прецедентов, а динамические - диаграммами взаимодействия, состояний и действий.

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

Вид с точки зрения процессов (Process view) охватывает нити и процессы, формирующие механизмы параллелизма и синхронизации в системе. Этот вид описывает главным образом производительность, масштабируемость и пропускную способность системы. В UML его статические и динамические аспекты визуализируются теми же диаграммами, что и для вида с точки зрения проектирования, но особое внимание при этом уделяется активным классам, которые представляют соответствующие нити и процессы.

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

Вид с точки зрения развертывания (Deployment view) охватывает узлы, формирующие топологию аппаратных средств системы, на которой она выполняется. В первую очередь он связан с распределением, поставкой и установкой частей, составляющих физическую систему. Его статические аспекты описываются диаграммами развертывания, а динамические - диаграммами взаимодействия, состояний и действий.

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

Жизненный цикл разработки ПО


Используя UML, вы практически не зависите от организации процесса разработки; он не привязан к какому-либо конкретному циклу изготовления программного продукта. Тем не менее, если вы хотите извлечь из этого языка наибольшую пользу, лучше всего применять процесс, который:

  • управляется прецедентами использования;

  • основан на архитектуре;

  • является итеративным и инкрементным.

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

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

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

Управляемый прецедентами, основанный на архитектуре, итеративный и ин-крементный процесс может быть разбит на фазы. Фазами (Phase) называют промежутки времени между двумя опорными точками процесса, в которых выполнены хорошо определенные цели, завершено создание артефактов и принимается решение, стоит ли переходить к следующей фазе. Как видно из рис. 2.21, жизненный цикл процесса разработки программного обеспечения состоит из четырех фаз: начало (Inception), исследование (Elaboration), построение (Construction) и внедрение (Transition). На этой диаграмме для каждой фазы показаны соответствующие производственные процессы. Нетрудно заметить, что в каждом из них с течением времени основные усилия сосредоточиваются на различных аспектах процесса разработки.



Рис. 2.21 . Жизненный цикл процесса разработки программного обеспечения

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

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

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

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

Во всех четырех фазах присутствует элемент, характерный для описанного способа организации разработки программного обеспечения, - итерация. Итерацией называется четко определенная последовательность действий с ясно сформулированным планом и критериями оценки, которая приводит к появлению новой версии для внешнего или внутреннего использования. Это означает, что жизненный цикл процесса разработки представляет собой непрерывный поток исполняемых версий, реализующих архитектуру системы. Взгляд на архитектуру как на важнейший элемент программной системы и послужил причиной того, что UML концентрируется на моделировании различных представлений системной архитектуры. (Обзор Рационального Унифицированного Процесса - Rational Unified Process - можно найти в "Приложении С"; более подробно он рассматривается в книге "The Unified Software Development Process".)



Глава 3. Здравствуй, мир!

  • Предисловие

  • Ключевые абстракции

  • Механизмы

  • Компоненты



Предисловие

Авторы языка Си (С) Брайан Керниган (Brian Kernighan) и Деннис Ричи (Dennis Ritchie) сказали как-то, что единственный способ выучить новый язык программирования - это писать на нем программы. Данное замечание верно и в отношении UML. Чтобы выучить этот язык, надо писать на нем модели.

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

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

Ключевые абстракции

На языке Java апплет для вывода на экран Web-браузера фразы "Здравствуй, мир!" не представляет собой ничего сложного:
import java.awt.Graphics;

class HelloWorld extends Java.applet.Applet {

public void paint (Graphics g) {

g.drawstring("Здравствуй, мир!", 10, 10);

}

}

Первая строка кода

import java.awt.Graphics;

делает класс Graphics доступным программе. Префикс java.awt определяет конкретный пакет Java, в котором содержится этот класс. Вторая строка

class HelloWorld extends Java.applet.Applet {

определяет новый класс HelloWorld и указывает, что он является разновидностью класса Applet, находящегося в пакете java . applet.

В следующих трех строках

public void paint (Graphics g) {

g.drawstring("Здравствуй, мир!", 10, 10);

}

объявляется операция с именем paint, при реализации которой вызывается другая операция, называемая drawstring, ответственная за вывод фразы "Здравствуй , мир!" в указанное место на экране. В полном соответствии с принятым в объектно-ориентированном программировании стиле drawString - это операция над параметром с именем g, типом которого является класс Graphics.

Моделирование этого приложения на языке UML не вызывает затруднений. Как видно из рис. 3.1, класс HelloWorld графически можно представить пиктограммой прямоугольника (информация о классах приводится в главах 4 и 9). Здесь же показана операция paint; ее формальные параметры скрыты, а реализация специфицирована в примечании.



Рис. 3.1 Ключевые абстракции класса HelloWorld



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



На этой диаграмме классов представлена суть приложения "Здравствуй, мир!", но многие детали опущены. Как видно из приведенного выше кода, в профамме задействованы два других класса - Applet и Graphics - и каждый по-разному. Applet является родителем HelloWorld, а класс Graphics необходим для реализации одной из его операций - paint. Эти классы и их отношения с классом HelloWorld можно изобразить в виде другой диаграммы классов (см. рис. 3.2).



Рис. 3.2 . Непосредственные соседи класса HelloWorld

Классы Applet и Graphics показаны в виде прямоугольных пиктограмм. Операции не представлены и на пиктограммах скрыты. Незакрашенная стрелка, направленная от класса HelloWorld к классу Applet, соответствует отношению обобщения; в данном случае это означает, что HelloWorld является потомком Applet. Пунктирная стрелка от класса HelloWorld к классу Graphics означает отношение зависимости (см. главы 5 и 10), поскольку HelloWorld использует класс Graphics.

Это, однако, еще не завершение структуры, лежащей в основе класса Hello-World. Изучив библиотеки языка Java, содержащие классы Applet и Graphics, вы обнаружите, что оба они являются частью более обширной иерархии. На рис. 3.3 показана диаграмма классов, которые расширяет и реализует класс HelloWorld.



Рис. 3.3 Иерархия наследования класса HelloWorld



Примечание: На этом рисунке приведен характерный пример диаграммы, созданной методом обратного проектирования готовой системы. Как вы уже знаете, обратное проектирование - это построение модели системы на основе ее кода.



Из рисунка видно, что HelloWorld - всего лишь листовой узел большой иерархии классов. Он выступает в качестве потомка класса Applet, который, в свою очередь, является потомком класса Panel, и так далее вплоть до Object -родителя всех классов в языке Java. Таким образом, данная модель соответствует библиотеке Java - у каждого класса есть родитель.

Отношение между элементами ImageObserver и Component отличается от остальных, и диаграмма классов передает это отличие. В библиотеке Java ImageObserver является интерфейсом (см. главу 11). Это означает, в частности, что у него нет реализации, а потому необходимо, чтобы его реализовывали другие классы. Как видно из рисунка, интерфейсы в UML обозначаются кружочком. О том, что класс Component реализует этот интерфейс, свидетельствует линия, направленная от реализации (Component) к интерфейсу (ImageObserver).

Итак, Не11oWorld непосредственно сотрудничает только с двумя классами (Applet и Graphics), но они являются всего лишь малой частью огромной библиотеки предопределенных классов Java. Для облегчения работы ее интерфейсы и классы организованы в виде нескольких пакетов. Корневой пакет среды разработки Java назван, как и следовало ожидать, java. Внутри него содержится несколько других пакетов, а внутри них - еще несколько пакетов, классы и интерфейсы. Класс Object заключен внутри пакета lang, так что его полное имя будет Java. lang.Object. Аналогично классы Panel, Container и Component содержатся в пакете awt, а класс Applet - в пакете applet. Интерфейс ImageObserver входит в состав пакета image, который, в свою очередь, находится в пакете awt, поэтому полное имя интерфейса будет выражено в виде довольно длинной строки j ava.awt.image.ImageObserver.

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

Рис. 3.4 Организация в пакеты классов, участвующих в приложении HelloWorld

Пакеты на языке UML изображают в виде папок с закладками (см. главу 12). Пакеты могут быть вложенными; существующие между ними зависимости показаны с помощью пунктирных стрелок. Например, класс HelloWorld зависит от пакета java.applet, a java.applet - от java.awt.

Механизмы

Наиболее значительная проблема, возникающая при освоении такой богатой библиотеки, как у языка Java, - понять, как ее части работают совместно. Как, например, вызывается функция paint в приложении HelloWorld? Какие операции следует использовать, чтобы изменить поведение этого апплета, например заставить его выводить строку другим цветом? Для ответа на эти и подобные вопросы необходимо иметь концептуальную модель, показывающую, как эти классы совместно работают в динамике. (Вам пригодится материал главы 28, где рассматриваются образцы поведения и каркасы.)

Как можно понять из библиотеки языка Java, операция paint наследуется от класса Component. Но все еще остается открытым вопрос, как происходит ее вызов. Ответ состоит в том, что paint вызывается в контексте нити (см. главу 22), в которой работает весь апплет, как показано на рис. 3.5.

Рис. 3.5 . Механизм изображения

На рисунке представлена кооперация нескольких объектов, включая один экземпляр класса HelloWorld. Другие объекты являются частью рабочей среды Java и в основном остаются на заднем плане создаваемых вами апплетов. В UML экземпляры (см. главу 11) изображаются в точности как классы, но, в отличие от последних, с подчеркнутыми именами. Первые три объекта на диаграмме являются анонимными, то есть не имеют уникального имени. Объекту HelloWorld принадлежит имя (target), известное объекту ComponentPeer.

Порядок событий можно моделировать с помощью диаграммы последовательностей (см. главу 18), представленной на рис. 3.5. Последовательность начинается с запуска объекта Thread, который вызывает операцию run объекта Toolkit. Объект Toolkit обращается затем к одной из своих собственных операций (callbackLoop), которая, в свою очередь, вызывает операцию handleExpose объекта ComponentPeer. Только после этого ComponentPeer обращается к операции paint целевого объекта. ComponentPeer предполагает, что целевой объект является экземпляром класса Component, но в данном случае мы фактически имеем дело с его потомком (а именно HelloWorld), так что полиморфно вызывается операция paint класса HelloWorld.

Компоненты

Программа "Здравствуй, мир!" реализована в виде апплета и поэтому не запускается самостоятельно, а существует как часть Web-страницы. Приложение начинает выполняться, только когда открывается содержащая его страница: запуск осуществляет механизм браузера, активизирующий выполнение объекта Thread этого апплета. Однако частью Web-страницы является не сам класс HelloWorld, а его двоичная форма, создаваемая компилятором Java, который преобразует исходный код в выполняемый компонент. Это позволяет взглянуть на систему совершенно с другой стороны. На всех предшествующих диаграммах мы видели логическое представление апплета, теперь же посмотрим на приложение как на набор физических компонентов (см. главу 25). Такой взгляд на систему представляет диаграмма компонентов (см. рис. 3.6).

Рис. 3.6 Компоненты HelloWorld

Каждая из показанных на этом рисунке пиктограмм соответствует элементу UML в представлении системы с точки зрения реализации. Компонент hello.java - это исходный код логического класса HelloWorld, то есть файл, которым можно манипулировать из среды разработки и с помощью инструментальных средств по управлению конфигурацией системы. Исходный код преобразуется в двоичный файл hellо.class компилятором Java, после чего может быть выполнен виртуальной машиной Java, установленной на компьютере.

Каноническая пиктограмма компонента - прямоугольник с двумя вкладками. Двоичный апплет HelloWorld.class является разновидностью этого символа, но границы прямоугольника толще, благодаря чему можно понять, что это исполняемый компонент (аналогично активному классу). Компоненту hello.java присвоена определенная пользователем пиктограмма, которая представляет текстовый файл. Аналогично и пиктограмма Web-страницы hello.html получена путем расширения нотации UML. Как видно из рисунка, в Web-страницу входит еще один компонент hello.jpg, также изображенный при помощи пользовательской пиктограммы, которая в данном случае содержит схематическое изображение рисунка. Так как последние три компонента представлены графическими символами, определенными пользователем, их имена расположены снаружи пиктограмм. (Механизмы расширения UML рассматриваются в главе 6.)



Примечание: Отношения между классом (HelloWorld), его исходным текстом (hello.java,) и объектным кодом (HelloWorld.class) редко моделируются явным образом, хотя иногда это и бывает полезно для визуализации физической конфигурации системы. С другой стороны, организацию Web-систем, подобных вышеприведенной, часто визуализируют с помощью диаграмм компонентов, с целью моделирования страниц и других исполняемых компонентов.


Часть II - Основы структурного моделирования

1   2   3   4   5   6   7   8   9   10

Похожие:

Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Оглавление введение зачем мы создаем доктрину
Макрос государственности глава “империя не умирает. Она передается” Глава потенциал русской цивилизации
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Методические рекомендации 8 Введение 10 часть первая введение в специальность....
Учебник предназначен для студентов высших учебных заведений, уча­щихся техникумов и колледжей, изучающих адаптивную физическую куль­туру,...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Методические рекомендации 8 Введение 10 часть первая введение в специальность....
Учебник предназначен для студентов высших учебных заведений, уча­щихся техникумов и колледжей, изучающих адаптивную физическую куль­туру,...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Д. С. Блинов (глава 6), Д. Ю. Гончаров (глава 8), М. А. Горбатова...
Истоки и современное содержание уголовной политики в области здравоохранения: актуальные вопросы теории и практики
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Малое руководство по дистилляции малое руководство по дистилляции часть 1: перегонный аппарат
Водяной пар проходит через колено («лебединую шею») и конденсируется в охладителе: это весь процесс. Физический процесс дистилляции...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Психоаналитические теории развития: интеграция часть процесс развития
Психоаналитические представления о познавательном (когнитивном) развитии. Глава отсутствует
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Общая психодиагностика
В. С. Аванесов глава 2 ( 2,1). В. С. Бабина глава 6 ( 4). Е. М. Борисова глава В. Б. Быстрицкас глава 7 ( 1). А. В. Визгина глава...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Учебное пособие общая психодиагностика
В. С. Аванесов глава 2 ( 2,1). В. С. Бабина глава 6 ( 4). Е. М. Борисова глава В. Б. Быстрицкас глава 7 ( 1). А. В. Визгина глава...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon 1. Методические аспекты проектирования программного обеспечения (ПО)
В курсе рассматриваются современные методы и средства анализа и проектирования программного обеспечения, основанные на применении...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Учебное пособие рпк «Политехник»
Авторы: Б. А. Карташов (главы 5, 6); Е. В. Матвеева (главы 1, 2); Т. А, Смелова (глава 3); А. Е. Гаврилов (введение, глава 4)
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Руководство пользователя Часть Руководство пользователя для Клиентов (пбс)
Подсистема управления расходами в части компонента, обеспечивающего функцию учета территориальными органами Федерального казначейства...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Руководство пользователя Часть Руководство пользователя для Клиентов (грбс, пбс)
Подсистема управления расходами в части компонента, обеспечивающего функцию учета территориальными органами Федерального казначейства...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Руководство исо/мэк 98-1: 2009 "Неопределенность измерения. Часть...
Неопределенность измерения. Часть Введение в руководства по неопределенности измерения
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Инструкция пользователя cms оглавление Глава 1 Справка 2 3 Глава...
Эта программа содержит множество функций и распределенную архитектуру с интегрированными окнами, учетными записями, различными языками,...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Инструкция пользователя
Важно: пожалуйста, внимательно прочитайте инструкцию, прежде чем начать пользоваться роботом. Глава Пульт Управления (краткое введение)...
Г буч, д рамбо, а джекобсон Язык uml руководство пользователя Часть I введение в процесс моделирования Глава Зачем мы моделируем icon Руководство пользователя Содержание
Введение стр. 2

Руководство, инструкция по применению




При копировании материала укажите ссылку © 2024
контакты
rykovodstvo.ru
Поиск