Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

2.3 Структурные паттерны

Лекция



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

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

2.3.1    Паттерн Adapter

Название

Adapter  (адаптер), Wrapper (обертка)

Задача

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

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

Результаты

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

Адаптер классов

  • Адаптирует Adaptee к Target, перепоручая действия конкретному классу Adaptee. Так как при наследовании структура программы остается жесткой, данный паттерн не будет работать, если мы захотим одновременно адаптировать класс и его подклассы.
  • Так как Adapter является подклассом Adaptee, мы можем легко заменить некоторые операции Adaptee.
  • Вводится только один новый объект. Что бы добраться до адаптируемого класса не нужно никаких дополнительных обращений по указателю.

Адаптер объектов

  • Позволяет одному адаптеру работать со многими адаптируемыми объектами (а самим Adaptee и со всеми его подклассами).
  • Затрудняет замещение операций Adaptee (так как Adapter не является подклассом Adaptee, мы можем использовать полиморфизм, только породив от Adaptee подкласс, заменив в нем операции Adaptee и заставив Adapter ссылаться на этот класс)

 

Структура

 

2.3      Структурные паттерны 

Рисунок 2.8 Структура паттерна Adapter (адаптер объектов)

 

2.3      Структурные паттерны 

 

Рисунок 2.9 Структура паттерна Adapter (адаптер классов)

 

2.3.2    Паттерн Composite

Название

Composite (компоновщик)

Мотивация

Такие приложения, как графические редакторы и редакторы электрических (схем, позволяют пользователям строить сложные диаграммы из более простых компонентов.

 2.3      Структурные паттерны

 

Рисунок 2.10 Структура паттерна Composite (пример)

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

Ключом к паттерну компоновщик является абстрактный класс, который представляет одновременно и примитивы, и контейнеры. В графической системе этот класс может называться Graphic. В нем объявлены операции, специфичные. Для каждого вида графического объекта (такие как Draw) и общие для всех составных объектов, например операции для доступа и управления потомками. Подклассы Line, Rectangle и Text (см. диаграмму выше) определяют примитивные графические объекты. В них операция Draw реализована соответственно для рисования прямых, прямоугольников и текста. Поскольку у примитивных объектов нет потомков, то ни один из этих подклассов не реализует операции, относящиеся к управлению потомками. Класс Picture определяет агрегат, состоящий из объектов Graphic. Реализованная в нем операция Draw вызывает одноименную функцию для каждого Потомка, а операции для работы с потомками уже не пусты. Поскольку интерфейс Класса Picture соответствует интерфейсу Graphic, то в состав объекта Picture Могут входить и другие такие же объекты. Ниже на диаграмме «оказана типичная структура составного объекта, рекурсивно скомпонованного из объектов класса Graphic.

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

 

Структура

 2.3      Структурные паттерны

 

Рисунок 2.11 Структура паттерна Composite

Результаты

  • определяет иерархии классов, состоящие из примитивных и составных объектов. Из примитивных объектов можно составлять более сложные, которые, в свою очередь, участвуют в более сложных композициях и так далее. Любой клиент, ожидающий примитивного объекта, может работать и с составным;
  • упрощает архитектуру клиента. Клиенты могут единообразно работать с индивидуальными и объектами и с составными структурами. Обычно клиенту неизвестно, взаимодействует ли он с листовым или составным объектом. Это упрощает код клиента, поскольку нет необходимости писать функции, ветвящиеся в зависимости от того, с объектом какого класса они работают;
  • облегчает добавление новых видов компонентов. Новые подклассы классов Composite или Leaf будут автоматически работать с уже существующими структурами и клиентским кодом. Изменять клиента при добавлении новых компонентов не нужно;
  • способствует созданию общего дизайна. Однако такая простота добавления новых компонентов имеет и свои отрицательные стороны; становится трудно наложить ограничения на то, какие объекты могут входить в состав композиции. Иногда желательно, чтобы составной объект мог включать только определенные виды компонентов. Паттерн компоновщик не позволяет воспользоваться для реализации таких ограничений статической системой типов. Вместо этого следует проводить проверки во время выполнения.

2.3.3    Паттерн Decorator

Название

Decorator (декоратор)

Задачи

Иногда бывает нужно возложить дополнительные обязанности на отдельный объект, а не на класс в целом. Так, библиотека для построения графических интерфейсов пользователя должна «уметь» добавлять новое свойство, скажем, рамку или новое поведение (например, возможность прокрутки к любому элемент у интерфейса). Добавить новые обязанности допустимо с помощью наследования. При наследовании классу с рамкой вокруг каждого экземпляра подкласса будет рисоваться рамка. Об этом говорит сайт https://intellect.icu . Однако это решение статическое, а значит, недостаточно гибкое. Клиент не может управлять оформлением компонента рамкой. Более гибким является другой подход: поместить компонент в другой объект, называемый декоратором, который как раз и добавляет рамку. Декоратор следует интерфейсу декорируемого объекта, поэтому его присутствие прозрачно для клиентов компонента. Декоратор переадресует запросы внутреннему компоненту, но может выполнять и дополнительные действия (например, рисовать рамку) до или после переадресации. Поскольку декораторы прозрачны, они могут вкладываться друг в друга, добавляя тем самым любое число новых обязанностей.

 2.3      Структурные паттерны

 

Рисунок 2.12 Структура паттерна Decorator (пример)

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

Классы ScrollDecorator и BorderDecorator являются подклассами Decorator - абстрактного класса, который представляет визуальные компоненты, применяемые для оформления других визуальных компонентов. VisualComponent - это абстрактный класс для представления визуальных объектов. В нем определен интерфейс для рисования и обработки событий. Отметим, что класс Decorator просто переадресует запросы на рисование своему компоненту, а его подклассы могут расширять эту операцию (см. рис. 2.13).

Структура

 2.3      Структурные паттерны

 

Рисунок 2.13 Структура паттерна Decorator

Результаты

У паттерна декоратор есть, по крайней мере, два плюса и два минуса:

  • большая гибкость, нежели у статического наследования. Паттерн декоратор позволяет более гибко добавлять объекту новые обязанности, чем было бы возможно в случае статического (множественного) наследования. Декоратор может добавлять и удалять обязанности во время выполнения программы. При использовании же наследования требуется создавать новый класс для каждой дополнительной обязанности (например, BorderedScrollableTextView, BorderedTextView), что ведет к увеличению числа классов и, как следствие, к возрастанию сложности системы. Кроме того, применение нескольких декораторов к одному компоненту позволяет произвольным образом сочетать обязанности. Декораторы позволяют легко добавить одно и то же свойство дважды. Например, чтобы окружить объект Textview двойной рамкой, нужно просто добавить два декоратора BorderDecorators. Двойное наследование классу Border в лучшем случае чревато ошибками;
  • позволяет избежать перегруженных функциями классов ни верхних уровнях иерархии. Декоратор разрешает добавлять новые обязанности по мере необходимости. Вместо того чтобы пытаться поддержать все мыслимые возможности в одном сложном, допускающем разностороннюю настройку классе, вы можете определить простой класс и постепенно наращивать его функциональность с помощью декораторов. В результате приложение уже не платит за неиспользуемые функции. Нетрудно также определять новые виды декораторов независимо от классов, которые они расширяют, даже если первоначально такие расширения не планировались. При расширении же сложного класса обычно приходится вникать в детали, не имеющие отношения к добавляемой функции;
  • декоратор и его компонент не идентичны. Декоратор действует как прозрачное обрамление. Но декорированный компонент все же не идентичен исходному. При использовании декораторов это следует иметь в виду;
  • множество мелких объектов. При использовании в проекте паттерна декоратор нередко получается система, составленная из большого числа мелких объектов, которые похожи друг на друга и различаются только способом взаимосвязи, а не классом и не значениями своих внутренних переменных. Хотя проектировщик, разбирающийся в устройстве такой системы, может легко настроить ее, но изучать и отлаживать ее очень тяжело.

2.3.4    Паттерн Facade

Название

Facade (фасад)

Назначение

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

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

Структура

2.3      Структурные паттерны 

Рисунок 2.14 Структура паттерна Facade

Участники

Facade – фасад.  Знает, каким классам подсистемы адресовать запрос; делегирует запросы клиентов подходящим объектам внутри подсистемы;

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

Отношения

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

Результаты

У паттерна фасад есть следующие преимущества:

  • изолирует клиентов от компонентов подсистемы, уменьшая тем самым число объектов, с которыми клиентам приходится иметь дело, и упрощая работу с подсистемой;
  • позволяет ослабить связанность между подсистемой и ее клиентами. Зачастую компоненты подсистемы сильно связаны. Слабая связанность позволяет видоизменять компоненты, не затрагивая при этом клиентов. Фасады помогают разложить систему на слои и структурировать зависимости между объектами, а также избежать сложных и циклических зависимостей. Это может оказаться важным, если клиент и подсистема реализуются независимо Уменьшение числа зависимостей на стадии компиляции чрезвычайно важно в больших системах. Хочется, конечно, чтобы время, уходящее на перекомпиляцию после изменения классов подсистемы, было минимальным. Сокращение числа зависимостей за счет фасадов может уменьшить количество нуждающихся в повторной компиляции файлов после небольшой модификации какой-нибудь важной подсистемы. Фасад может также упростить процесс переноса системы на другие платформы, поскольку уменьшается вероятность того, что в результате изменения одной подсистемы понадобится изменять и все остальные;
  • фасад не препятствует приложениям напрямую обращаться к классам подсистемы, если это необходимо. Таким образом, у вас есть выбор между простотой и общностью.

2.3.5    Паттерн Low Coupling

Название

Low Coupling (Низкая связность)

Проблема          

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

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

  • Изменения в связанных классах приводят к локальным изменениям в данном классе.
  • Затрудняется понимание каждого класса в отдельности.
  • Усложняется повторное использование, поскольку для этого требуется дополнительный анализ классов, с которыми связан данный класс.

Решение

Распределить обязанности таким образом, чтобы степень связанности оставалась низкой.

Результаты

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

Пример

Пусть в системе имеются классы Payment, Sale и Register. Предположим, что необходимо создать экземпляр класса Payment и связать его с объектом Sale. Какой класс должен отвечать за выполнение этой операции? Поскольку в реальной предметной области регистрация объекта Payment выполняется объектом Register, в соответствии с шаблоном Creator, объект Register является хорошим кандидатом для создания объекта Payment. Затем экземпляр объекта Register должен передать сообщение addPayment объекту Sale, указав в качестве параметра новый объект Payment. Приведенные рассуждения отражены на фрагменте диаграммы взаимодействий, представленной на рис. 2.15.Такое распределение обязанностей предполагает, ЧТО класс Register обладает знаниями о данных класса Payment (т.е. связывается с ним).

Обратите внимание на обозначения, принятые в языке UML. Экземпляру объекта Payment присвоено явное имя р, чтобы его можно было использовать в качестве параметра сообщения 2.

2.3      Структурные паттерны 

Рисунок 2.15 Диаграмма взаимодействия. Сильная связность

Альтернативный способ создания объекта Payment и его связывания с объектом Sale состоит в том, что бы возложит обязанность за создание объекта Payment на Sale (рис. 2.16)

 2.3      Структурные паттерны

Рисунок 2.16  Диаграмма взаимодействия. Слабая связность

Когда не следует применять шаблон

Высокая степень связывания с устойчивыми элементами не представляет проблемы. Например, приложение J2EE можно жестко связать с библиотеками Java (java.util и т.п.), поскольку эти библиотеки широко распространены и стабильны.

Выбери свою игру

Высокая степень связывания сама по себе не является проблемой. Проблемой является жесткое связывание с неустойчивыми в некотором отношении элементами.

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

2.3.6    Паттерн Information Expert

Название

Information Expert (информационный эксперт)

Проблема          

Каков наиболее общий принцип распределения обязанностей между объектами при объектно-ориентированном проектировании?

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

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

Решение

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

Результаты

Соответствующее поведение системы обеспечивается несколькими классами содержащими требуемую информацию. Это приводит к определениям классов, которые гораздо проще понимать и поддерживать. Кроме того, поддерживается шаблон High Cohesion

Пример

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

Какой класс должен отвечать за знание общей суммы продажи?

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

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

Ответ на этот вопрос сводится к следующему:

Если в модели проектирования имеются соответствующие классы, в первую очередь, следует использовать ее.

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

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

Чтобы рассмотреть этот пример подробнее, обратимся к фрагменту модели предметной области, представленному на рис. 2.17.

2.3      Структурные паттерны 

Рисунок 2.17 Фрагмент модели предметной области

Какая информация требуется для вычисления общей суммы? Необходимо узнать стоимость всех проданных товаров SalesLineltem и просуммировать эти промежуточные суммы. Такой информацией обладает лишь экземпляр объекта Sale. Следовательно, с точки зрения шаблона Information Expert объект Sale v подходит для выполнения этой обязанности, т.е. является информационным экспертом (information expert).

Как уже упоминалось, подобные вопросы распределения обязанностей зачастую возникают при создании диаграмм взаимодействий. Представьте, что вы приступили к работе, начав создание диаграмм для распределения обязанностей между объектами. Принятые решения иллюстрируются на фрагменте диаграммы Взаимодействий, представленном на рис. 2.18.

Однако на данном этапе выполнена не вся работа. Какая информация требуется для вычисления промежуточной суммы элементов продажи? Необходимы значения атрибутов SalesLineltem.quantity и SalesLineltem.price. Объекту SalesLineltem известно количество товара и известен связанный с ним объект ProductSpecif ication. Следовательно, в соответствии с шаблоном Expert, промежуточную сумму должен вычислять объект SalesLineltem. Другими словами, этот объект является информационным экспертом.

2.3      Структурные паттерны 

Рисунок 2.18 Распределение обязанностей в соответствии с паттерном Information Expert

В терминах диаграмм взаимодействий это означает, что объект Sale должен передать сообщения getSubtotal каждому объекту SalesLineltem, а затем просуммировать полученные результаты. Этот процесс проиллюстрирован на рис. 2.19

2.3      Структурные паттерны 

Рисунок 2.19 Распределение обязанностей в соответствии с паттерном Information Expert

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

В завершение можно сказать следующее. Для выполнения обязанности "знать и предоставлять общую сумму продажи трем объектам классов" были следующим образом присвоены три обязанности:

  • Sale - знание общей суммы продажи
  • SalesLineltem - знание промежуточной суммы для данного товара
  • Product Specification - нание цены товара

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

2.3      Структурные паттерны 

Рисунок 2.20 Распределение обязанностей в соответствии с паттерном Information Expert

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

Ответы на вопросы для самопроверки пишите в комментариях, мы проверим, или же задавайте свой вопрос по данной теме.

создано: 2014-10-05
обновлено: 2021-03-13
132649



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Объектно-ориентированное программирование ООП

Термины: Объектно-ориентированное программирование ООП