'

Технология разработки программного обеспечения (вторая часть) Структурные шаблоны проектирования ПО

Понравилась презентация – покажи это...





Слайд 0

Технология разработки программного обеспечения (вторая часть) Структурные шаблоны проектирования ПО проф. каф. ОСУ Тузовский А.Ф. Лекция 6


Слайд 1

2. Структурные паттерны Описывают способы построение сложных структур из классов и объектов. Adapter Bridge Facade Composite Decorator Flyweight Proxy


Слайд 2

Паттерн Adapter (Адаптер) Цель паттерна Adapter (адаптер) – привести (адаптировать) интерфейс некоторого адаптируемого класса к интерфейсу, который ожидается клиентом. Основные понятия: клиент (client) -- класс, который использует (в общем случае агрегирует) некоторый класс, который мы называем адаптируемым (adaptee). адаптер (adapter) -- класс, выполняющий приведение интерфейса адаптируемого класса к интерфейсу, ожидаемому клиентом.


Слайд 3

Причина возникновения паттерна Проблема: имеется некоторый класс, который нужно использовать в необычной для его структуры задаче. Например, есть тип данных, описывающий понятие сетевого устройства (IPEndPoint), который имеет такими свойствами как IP- адрес, мак-адрес и имя хоста. Его нужно использовать для решения некоторой задачи (например, трассировки перемещения пакетов).


Слайд 4

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


Слайд 5

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


Слайд 6

Структура паттерна Adapter


Слайд 7

Участвующие элементы Client - класс, который использует некоторые вспомогательные типы данных и ожидает, что они имеют стандартный интерфейс взаимодействия (использования) описанный классом Target. Target - класс, имеющий интерфейс, ожидаемый клиентом. Adaptee - класс, необходимый для работы клиента, но имеет интерфейс, отличный от того, который ожидается клиентом. Adapter - класс, выполняющий приведение интерфейса класса Adaptee, к интерфейсу класса Target.


Слайд 8

Приведение интерфейса выполняется за счёт того, что класс Adapter наследует оба класса Adaptee и Target значит, обладает интерфейсами обоих этих классов. Затем класс Adapter приводит вызовы методов специфичных для интерфейса класса Target к вызовам соответствующих методов интерфейса класса Apadtee.


Слайд 9

Диаграмма последовательности


Слайд 10

Альтернативный способ


Слайд 11

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


Слайд 12


Слайд 13

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


Слайд 14

Основной результат использования паттерна Adapter (2) Увеличивает гибкость и масштабируемость создаваемых приложений за счёт модульной структуры готового приложения. Расширять приложение путём добавления новых типов значительно проще, чем полностью заново создавать некоторые модули.


Слайд 15

Пример использования паттерна Есть приложение, выполняющее управление товарооборотом предприятия; Используется тип данных Product (продукт/товар), который будет организован в коллекцию товаров при помощи класса ProductsCollection; мы решили сделать так, чтобы можно было все данные экспортировать в отдельные xml-файлы. Для этого мы реализовали класс XmlIO, которые осуществляет запись и чтение Xml-документа, и объект которого инкапсулируется оконным классом нашего приложения.


Слайд 16

Класс ProductXmlIOAdapter, Для записи в файл коллекции продуктов создается класс ProductXmlIOAdapter инкапсулирует коллекцию продуктов, выполняет приведение этой коллекции к XML-документу, выполняет приведение XML-документа к коллекции. При этом не меняется структура исходного типа данных и устраняется избыточность структуры, которая могла появиться вследствие наполнения класса Product дополнительным функционалом.


Слайд 17

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


Слайд 18

Диаграмма классов, иллюстрирующая приложение


Слайд 19

Прототип Адаптер


Слайд 20


Слайд 21


Слайд 22


Слайд 23


Слайд 24


Слайд 25


Слайд 26

Паттерн Facade (Фасад) Паттерн Facade (Фасад ) применяется, когда нужно предоставить простой специализированный интерфейс к группе объектов, имеющих сложный общий интерфейс. Пример: есть интерфейсы классов из пространства имен System.Data (ADO.Net). Нужно сделать простой интерфейс, специфичный для данных ProductData.


Слайд 27

Класс Db Накладывает очень простой интерфейс, специфичный для ProductData, на сложные общие интерфейсы классов из пространства имен System.Data. избавляет Application от необходимости вникать в тонкости пространства имен System.Data. скрывает общность и сложность System.Data за простым специализированным интерфейсом.


Слайд 28

Класс DB, являющийся частным случаем Фасада – определяет политику использования System.Data. Класс DB описывает: как открыть и закрыть соединение с базой данных, как установить соответствие между переменными-членами ProductData и полями базы данных, как строить запросы для манипулирования данными. Вся эта сложность скрыта от пользователя.


Слайд 29

С точки зрения Application пространства имен System.Data вообще не существует, оно скрыто за Фасадом. Использование паттерна Фасад подразумевает следующее: разработчики согласны с тем, что все обращения к базе данных должны производиться только через класс DB.


Слайд 30

Паттерн Mediator (Посредник) Например, класс QuickEntryMediator находится за сценой и привязывает текстовое поле ввода к списку. Когда вы вводите текст в поле, первый элемент списка, начинающийся с введенной строки, подсвечивается. Это позволяет набирать только начало текста и затем производить быстрый выбор из списка.


Слайд 31

Класс QuickEntryMediator Принимает объекты TextBox и ListBox. Предполагается, что пользователь будет вводить в TextBox префиксы строк, находящихся в ListBox Класс автоматически выбирает первый элемент ListBox, который начинается с префикса, введенного в TextBox. Если значение в поле TextBox равно null или префикс не соответствует никакому элементу ListBox, то выделение в ListBox снимается. В этом классе нет открытых методов. Нужно просто создать объект класса и QuickEntryMediator и забываете о его существовании. Например: TextBox t = new TextBox(); ListBox l = new ListBox(); QuickEntryMediator qem = new QuickEntryMediator(t, l);


Слайд 32

Kласс QuickEntryMediator using System; using System.Windows.Forms; public class QuickEntryMediator { private TextBox itsTextBox; private ListBox itsList; public QuickEntryMediator(TextBox t, ListBox l) { itsTextBox = t; itsList = l; itsTextBox.TextChanged += new EventHandler(TextFieldChanged); } private void TextFieldChanged(object source, EventArgs args) { string prefix = itsTextBox.Text; if (prefix.Length == 0) { itsList.ClearSelected(); return; } ListBox.ObjectCollection listItems = itsList.Items; bool found = false; for (int i = 0; found == false && i < listItems.Count; i++) { object o = listItems[i]; string s = o.ToString(); if (s.StartsWith(prefix)) { itsList.SetSelected(i, true); found = true; } } if (!found) { itsList.ClearSelected(); } } }


Слайд 33

Структура класса QuickEntryMediator Конструктору экземпляра QuickEntryMediator передаются ссылки на ListBox и TextBox. QuickEntryMediator назначает обработчик события TextChanged для объекта TextBox. при любом изменении текста вызывает метод TextFieldChanged, который ищет в списке ListBox элемент, начинающийся с текущего значения текстового поля, и выделяет его. Пользователи классов ListBox и TextField понятия не имеют о существовании этого Посредника. Он находится в сторонке и незаметно накладывает свою политику на объекты, не спрашивая у них разрешения и даже не ставя их в известность.


Слайд 34

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


Слайд 35

Заместитель и Шлюз: управление сторонними API


Слайд 36

Паттерн Заместитель


Слайд 37


Слайд 38


Слайд 39


Слайд 40


Слайд 41


Слайд 42


Слайд 43


Слайд 44


Слайд 45


Слайд 46


Слайд 47


Слайд 48


Слайд 49


Слайд 50


Слайд 51


Слайд 52


Слайд 53


Слайд 54


Слайд 55


Слайд 56


Слайд 57


Слайд 58


Слайд 59


Слайд 60


Слайд 61


Слайд 62


Слайд 63


Слайд 64


Слайд 65


Слайд 66

Паттерн Bridge (мост) Цель паттерна Bridge («мост») – отделить абстракцию от её реализации, чтобы они могли изменяться независимо друг от друга.


Слайд 67

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


Слайд 68

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


Слайд 69

Структура паттерна Bridge


Слайд 70

Участники паттерна Bridge Abstraction (абстракция) - определяет интерфейс абстракции, а также содержит объект исполнителя, который определяет интерфейс реализации. Implementor (исполнитель) – определяет интерфейс для классов реализации. интерфейс исполнителя не обязательно должен соответствовать интерфейсу абстракции. интерфейсы, определённые абстракцией и исполнителем, могут быть совершенно разными, что является достаточно гибким. В целом, исполнитель должен определять базовые операции, на которых впоследствии базируется высокоуровневая логика абстракции. RefinedAbstraction (уточнённая абстракция) - расширяет интерфейс определённый абстракцией. Concretelmplementor (конкретизированный исполнитель) - класс, который реализует интерфейс исполнителя и определяет его частную реализацию. Абстракция и исполнитель совместно образуют «мост», который связывает уточнённую абстракцию с конкретной реализацией.


Слайд 71

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


Слайд 72

Пример использования паттерна Bridge Смешанный графический редактор – позволяет совместно, в рамках одного представления, редактировать растровую и векторную графику. Приложение работает с некоторыми абстрактными фигурами, использующими интерфейсом Figure. Интерфейс исполнителя определяется интерфейсом Figurelmp, от которого мы наследуем классы VectorFigure и RasterFigure - соответственно, описывающих реализации прорисовки векторной и растровой фигур. После определения реализации мы можем уточнить абстракцию, описав интерфейса некоторой конкретной фигуры (например, эллипса). После этого можно связать уточнённую абстракцию с конкретной реализацией, например, определив классы VectorEllipse и RasterEllipse, описывающие соответственно векторный и растровый эллипсы.


Слайд 73

Модель описанного выше приложения


Слайд 74

Паттерн Composite (Компоновщик) Паттерн Composite (Компоновщик) – очень простой паттерн, имеющий широкое применение. Например, есть иерархия классов геометрических фигур. У базового класса Shape есть два подкласса: Circle и Square. Третьим подклассом является компоновщик.


Слайд 75

Пример паттерна Composite (Компоновщик) В классе CompositeShape хранится список объектов типа Shape. метод Draw() в этом классе последовательно вызывает метод Draw() каждого объекта в списке. Экземпляр CompositeShape выглядит для системы как один объект Shape. Его можно передать любому методу, принимающему Shape, и он будет вести себя, как Shape. Однако это заместитель группы объектов Shape.


Слайд 76

Реализация класса CompositeShape public interface Shape { void Draw(); } using System.Collections; public class CompositeShape : Shape { private ArrayList itsShapes = new ArrayList(); public void Add(Shape s) { itsShapes.Add(s); } public void Draw() { foreach (Shape shape in itsShapes) shape.Draw(); } }


Слайд 77

Составные команды Ранее рассматривались объекты Sensor и Command. Обнаружив событие, объект-датчик Sensor вызывал метод Do() ассоциированного с ним объекта Command. Часто Sensor должен выполнять несколько команд. Например, дойдя до определенного места на тракте подачи, лист бумаги закрывает оптический датчик. в этот момент датчик останавливает один двигатель, запускает другой и включает определенную муфту.


Слайд 78


Слайд 79


Слайд 80


Слайд 81


×

HTML:





Ссылка: