Основные принципы проектирование приложений 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Основные принципы проектирование приложений



Архитектура приложений.

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

Необходимо помнить, что архитектура должна:

 Раскрывать структуру системы, но скрывать детали реализации.

 Реализовывать все варианты использования и сценарии.

 По возможности отвечать всем требованиям различных заинтересованных сторон.

 Выполнять требования, как по функциональности, так и по качеству.

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

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

 

 

Рис. 1 Пользователь, бизнес, система

Необходимо искать компромиссы и находить баланс между конкурирующими требованиями этих трех областей.

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

 

 

2. Как можно улучшить адаптируемость приложения к будущим требованиям?

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

Рассмотрим следующие основные направления:

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

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

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

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

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

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

 

Многослойная архитектура

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

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

Рассмотрим общие принципы проектирования с использованием многослойной архитектуры:

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

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

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

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

Возможность повторного использования. Отсутствие зависимостей между нижними и верхними слоями обеспечивает потенциальную возможность их повторного использования в других сценариях.

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

 

Рекомендаций по проектирование слоев типовой архитек прилож.

Архитектура ПО часто описывается как организация или структура системы, где система представляет набор компонентов, выполняющих определенную функцию или набор функций. Иначе говоря, основное назначение архитектуры – организация компонентов с целью обеспечения определенной функциональности. Такую организацию функциональности часто называют группировкой компонентов по «функциональным областям». На рис. 1 представлена типовая архитектура приложения, компоненты которого сгруппированы по функциональным областям.

 

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

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

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

 

Слой сервисов

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

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

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

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

Слои приложения

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

Явно определяйте связи между слоями. Решение, в котором каждый слой приложения может взаимодействовать или имеет зависимости со всеми остальными слоями, является сложным для понимания и управления. Принимайте явные решения о зависимостях между слоями и о потоках данных между ними.

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

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

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

Архитектура.NET Framework

Платформа состоит из четырех групп программных продуктов:

· набор языков, куда входят С# и VisualBasic.NET; набор инструментальных средств разработки, в том числе VisualStudio.NET; обширная библиотека классов для построения Web-служб и приложений, работающих в Windows и в Интернете; а также среда выполнения программ CLR (CommonLanguageRuntime — общеязыковая среда выполнения), в которой выполняются объекты, построенные на этой платформе;

· набор серверов.NET EnterpriseServers, ранее известных под именами SQL Server 2000, Exchange 2000, BizTalk 2000 и др., которые предоставляют специализированные функциональные возможности для обращения к реляционным базам данных, использования электронной почты, оказания коммерческих услуг "бизнес-бизнес" (В2В) и т. д.;

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

· новые некомпьютерные устройства, поддерживающие средства.NET, — от сотовых телефонов до игровых приставок.

Microsoft.NET поддерживает не только языковую независимость, но и языковую интеграцию. Это означает, что разработчик может наследовать от классов, обрабатывать исключения и использовать преимущества полиморфизма при одновременной работе с несколькими языками. Платформа.NET Framework предоставляет такую возможность с помощью спецификации CTS (CommonTypeSystem — общая система типов), которая полностью описывает все типы данных, поддерживаемые средой выполнения, определяет, как одни типы данных могут взаимодействовать с другими и как они будут представлены в формате метаданных.NET. Например, в.NET любая сущность является объектом какого-нибудь класса, производного от корневого класса System.Object. Спецификация CTS поддерживает такие общие понятия, как классы, делегаты (с поддержкой обратных вызовов), ссылочные и размерные типы.

Важно понимать, что не во всех языках программирования.NET обязательно должны поддерживаться все типы данных, которые определены в CTS. Спецификация CLS (CommonLanguageSpecification — общая языковая спецификация) устанавливает основные правила, определяющие законы, которым должны следовать все языки: ключевые слова, типы, примитивные типы, перегрузки методов и т. п. Спецификация CLS определяет минимальные требования, предъявляемые к языку платформы.NET. Компиляторы, удовлетворяющие этой спецификации, создают объекты, способные взаимодействовать друг с другом. Любой язык, соответствующий требованиям CLS, может использовать все возможности библиотеки FCL (FrameworkClassLibrary — библиотека классов платформы). CLS позволяет и разработчикам, и поставщикам, и производителям программного обеспечения не выходить за пределы общего набора правил для языков, компиляторов и типов данных.

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

· четыре официальных языка: С#, VB.NET, Managed C++ (управляемый C++) и JScript.NET;

· объектно-ориентированную среду CLR (CommonLanguageRuntime), совместно используемую этими языками для создания приложений под Windows и для Internet;

· ряд связанных между собой библиотек классов под общим именем FCL (FrameworkClassLibrary).

Отношения архитектурных компонентов платформы.NET Framework с концептуальной точки зрения представлены на рис. 1.2.


Рис. 1.2. Архитектура.NET Framework

 

Самым важным компонентом платформы.NET Framework является CLR (CommonLanguageRuntime), предоставляющая среду, в которой выполняются программы. Главная ее роль заключается в том, чтобы обнаруживать и загружать типы.NET и производить управление ими в соответствии с полученными командами. CLR включает в себя виртуальную машину, во многих отношениях аналогичную виртуальной машине Java. На верхнем уровне среда активизирует объекты, производит проверку безопасности, размещает объекты в памяти, выполняет их, а также запускает сборщик мусора.

Под сборкой мусора понимается освобождение памяти, занятой объектами, которые стали бесполезными и не используются в дальнейшей работе приложения. В ряде языков программирования (например, C/C++) память освобождает сам программист, в явной форме отдавая команды как на создание, так и на удаление объекта. В этом есть своя логика — "я тебя породил, я тебя и убью". Однако в CLR задача сборки мусора (и другие вопросы, связанные с использованием памяти) решается в нужное время и в нужном месте исполнительной средой, ответственной за выполнение вычислений.

На рис. 1.2 над уровнем CLR находится набор базовых классов платформы, над ним расположены слой классов данных и XML, а также слой классов для создания Web-служб (WebServices), Web- и Windows-приложений (WebForms и WindowsForms). Собранные воедино, эти классы известны под общим именем FCL (FrameworkClassLibrary). Это одна из самых больших библиотек классов в истории программирования. Она открывает доступ к системным функциям, включая и те, что прежде были доступны только через API Windows, а также к прикладным функциям для Web-разработки (ASP.NET), доступа к данным (ADO.NET), обеспечения безопасности и удаленного управления. Имея в своем составе более 4000 классов, библиотека FCL способствует быстрой разработке настольных, клиент-серверных и других приложений и Web-служб.

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

Над этим уровнем находится уровень классов, которые расширяют базовые классы с целью обеспечения управления данными и XML. Классы данных позволяют реализовать управление информацией, хранящейся в серверных базах данных. В число этих классов входят классы SQL (StructuredQueryLanguage, язык структурированных запросов), дающие программисту возможность обращаться к долговременным хранилищам данных через стандартный интерфейс SQL. Кроме того, набор классов, называемый ADO.NET, позволяет оперировать постоянными данными. Платформа.NET Framework поддерживает также целый ряд классов, позволяющих манипулировать XML-данными и выполнять поиск и преобразования XML.

Базовые классы, классы данных и XML расширяются классами, предназначенными для построения приложений на основе трех различных технологий: WebServices (Web-службы), WebForms (Web-формы) и WindowsForms (Windows-формы). Web-службы включают в себя ряд классов, поддерживающих разработку облегченных распределяемых компонентов, которые могут работать даже с брандмауэрами и программами трансляции сетевых адресов (NAT). Поскольку Web-службы применяют в качестве базовых протоколов связи стандартные протоколы HTTP и SOAP, эти компоненты поддерживают в киберпространстве подход "Plug&Play".

Инструментальные средства WebForms и WindowsForms позволяют применять технику RAD (RapidApplicationDevelopment — быстрая разработка приложений) для построения Web- и Windows-приложений. Эта техника сводится к перетаскиванию элементов управления с панели инструментов на форму, двойному щелчку по элементу и написанию кода, который обрабатывает события, связанные с этим элементом.

 

Архитектура приложений.

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

Необходимо помнить, что архитектура должна:

 Раскрывать структуру системы, но скрывать детали реализации.

 Реализовывать все варианты использования и сценарии.

 По возможности отвечать всем требованиям различных заинтересованных сторон.

 Выполнять требования, как по функциональности, так и по качеству.

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

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

 

 

Рис. 1 Пользователь, бизнес, система

Необходимо искать компромиссы и находить баланс между конкурирующими требованиями этих трех областей.

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

 

 

2. Как можно улучшить адаптируемость приложения к будущим требованиям?

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

Рассмотрим следующие основные направления:

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

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

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

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

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

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

 

Основные принципы проектирование приложений

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

Рассмотрим основные принципы:

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

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

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

 

Разделение функций. Разделите приложение на отдельные компоненты с, по возможности, минимальным перекрытием функциональности. Важным фактором является предельное уменьшение количества точек соприкосновения, что обеспечит высокую связность (highcohesion) и слабую связанность (lowcoupling).

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

Принцип минимального знания (также известный как Закон Деметера (LawofDemeter, LoD)). Компоненту или объекту не должны быть известны внутренние детали других компонентов или объектов.

Неповторяйтесь (Don’t repeat yourself, DRY). Намерение должно быть обозначено только один раз. В применении к проектированию приложения это означает, что определенная функциональность должна быть реализована только в одном компоненте и не должна дублироваться ни в одном другом компоненте.

Минимизируйте проектирование наперед. Проектируйте только то, что необходимо. В некоторых случаях, когда стоимость разработки или издержки в случае неудачного дизайна очень высоки, может потребоваться полное предварительное проектирование и тестирование. В других случаях, особенно при гибкой разработке, можно избежать масштабного проектирования наперед (bigdesignupfront, BDUF).

 

 



Поделиться:


Последнее изменение этой страницы: 2017-02-09; просмотров: 3070; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 35.175.212.5 (0.089 с.)