Виды паттернов проектирования. Структурные паттерны. 


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



ЗНАЕТЕ ЛИ ВЫ?

Виды паттернов проектирования. Структурные паттерны.



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

примитивных и составных. Последние позволяют создавать произвольно сложные

структуры из примитивных и других составных объектов. В паттерне заместитель

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

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

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

Паттерн Adapter.

1)Название и классификация паттерна

Адаптер - паттерн, структурирующий классы и объекты.

2)Назначение

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

3)Известен также под именем

Wrapper (обертка).

4) Применимость

Применяйте паттерн адаптер, когда:

□ хотите использовать существующий класс, но его интерфейс не соответствует вашим потребностям;

□ собираетесь создать повторно используемый класс, который должен взаимодействовать с заранее неизвестными или не связанными с ним классами, имеющими несовместимые интерфейсы;

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

5)Участники

□Target (Shape) - целевой:

- определяет зависящий от предметной области интерфейс, которым

пользуется Client;

□Client (DrawingEditor) - клиент:

- вступает во взаимоотношения с объектами, удовлетворяющими

интерфейсу Target;

□Adaptee (TextView) - адаптируемый:

- определяет существующий интерфейс, который нуждается в адаптации;

□ Adapter (TextShape) - адаптер:

- адаптирует интерфейс Adaptee к интерфейсу Target.

6)Отношения

Клиенты вызывают операции экземпляра адаптера Adapter. B свою очередь адаптер вызывает операции адаптируемого объекта или класса Adaptee, который и выполняет запрос.

7) Результаты

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

класса:

□ адаптирует Adaptee к Target, перепоручая действия конкретному классу Adaptee. Поэтому данный паттерн не будет работать, если мы захотим одновременно адаптировать класс и его подклассы;

□ позволяет адаптеру Adapter заместить некоторые операции адаптируемого класса Adaptee, так как Adapter есть не что инос, как подкласс Adaptee;

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

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

□ позволяет одному адаптеру Adapter работать со многим адаптируемыми объектами Adaptee, то есть с самим Adaptee и его подклассами (если таковые имеются). Адаптер может добавить новую функциональность сразу всем адаптируемым объектам;

□ затрудняет замещение операций класса Adaptee. Для этого потребуется породить от Adaptee подкласс и заставить Adapter ссылаться на этот подкласс, а не на сам Adaptee.

8) Родственные паттерны

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

Паттерн Composite.

1)Название и классификация паттерна

Компоновщик - паттерн, структурирующий объекты.

2)Назначение

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

3) Применимость

Используйте паттерн компоновщик, когда:

□ нужно представить иерархию объектов вида часть-целое;

□ хотите, чтобы клиенты единообразно трактовали составные и индивидуальные объекты.

4) Участники

□Component (Graphic) - компонент:

- объявляет интерфейс для компонуемых объектов;

- предоставляет подходящую реализацию операций по умолчанию, общую

для всех классов;

- объявляет интерфейс для доступа к потомкам и управления ими;

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

□ Leaf (Rectangle, Line, Text, и т.п.) - ЛИСТ:

- представляет листовые узлы композиции и не имеет потомков;

- определяет поведение примитивных объектов в композиции;

□ Composite (Picture) - составной объект:

- определяет поведение компонентов, у которых есть потомки;

- хранит компоненты-потомки;

- реализует относящиеся к управлению потомками операции в интерфейсе класса Component;

□ Client - клиент:

- манипулирует объектами композиции через интерфейс Component.

5)Отношения

Клиенты используют интерфейс класса Component для взаимодействия с

объектами в составной структуре. Если получателем запроса является листовый объект

Leaf, то он и обрабатывает запрос. Когда же получателем является составной объект

Composite, то обычно он перенаправляет запрос своим потомкам, возможно,

выполняя некоторые дополнительные операции до или после перенаправления.

6) Результаты

Паттерн компоновщик:

□определяет иepapxии классов, состоящие из примитивных и составных объектов. Из примитивных объектов можно составлять более сложные, которые, в свою очередь, участвуют в более сложных композициях и так далее.Любой клиент, ожидающий примитивного объекта, может работать и с составным;

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

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

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

7) Родственные паттерны

Отношение компонент-родитель используется в паттерне цепочка

обязанностей. Паттерн декоратор часто применяется совместно с компоновщиком. Когда

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

Паттерн Flyweight.

1)Название и классификация паттерна

Приспособленец - паттерн, структурирующий объекты.

2)Назначение

Использует разделение для эффективной поддержки множества мелких объектов.

3)Мотивация

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

4) Применимость

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

□ в приложении используется большое число объектов;

□ из-за этого накладные расходы на хранение высоки;

□ большую часть состояния объектов можно вынести вовне;

□ многие группы объектов можно заменить относительно небольшим

количеством разделяемых объектов, поскольку внешнее состояние вынесено;

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

5) Участники

□ Flyweight (Glyph) - приспособленец:

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

□ConcreteFlyweight (Character) - конкретный приспособленец:

- реализует интерфейс класса Flyweight и добавляет при необходимости внутреннее состояние. Объект класса ConcreteFlyweight должен быть разделяемым. Любое сохраняемое им состояние должно быть внутренним, то есть не зависящим от контекста;

□ UnsharedConcreteFlyweight (Row, Column) - неразделяемый конкретный риспособленец:

- не все подклассы Flyweight обязательно должны быть разделяемыми.

Интерфейс Flyweight допускает разделение, но не навязывает его. Часто у объектов UnsharedConcreteFlyweight на некотором уровне структуры приспособленца есть потомки в виде объектов класса ConcreteFlyweight, как, например, у объектов классов Row и Column;

□ FlyweightFactory - фабрика приспособленцев:

- создает объекты-приспособленцы и управляет ими;

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

□ Client - клиент:

- хранит ссылки на одного или нескольких приспособленцев;

- вычисляет или хранит внешнее состояние приспособленцев.

6) Отношения

□ состояние, необходимое приспособленцу для нормальной работы, можно охарактеризовать как внутреннее или внешнее. Первое хранится в самом объекте ConcreteFlyweight. Внешнее состояние хранится или вычисляется клиентами. Клиент передает его приспособленцу при вызове операций;

□ клиенты не должны создавать экземпляры класса ConcreteFlyweight напрямую, а могут получать их только от объекта FlyweightFactory. Это позволит гарантировать корректное разделение.

7) Результаты

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

Экономия памяти возникает по ряду причин:

□уменьшение общего числа экземпляров;

□ сокращение объема памяти, необходимого для хранения внутреннего состояния;

□ вычисление, а не хранение внешнего состояния (если это действительно так).

Чем выше степень разделения приспособленцев, тем существеннее экономия.

8) Родственные паттерны

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

Паттерн Proxy.

1)Название и классификация паттерна

Заместитель - паттерн, структурирующий объекты.

2)Назначение

Является суррогатом другого объекта и контролирует доступ к нему.

3)Известен также под именем

Surrogate (суррогат).

4) Применимость

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

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

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

□ «умная» ссылка - это замена обычного указателя. Она позволяет выполнить

дополнительные действия при доступе к объекту.

5) Участники

□ Proxy (ImageProxy) - заместитель:

- хранит ссылку, которая позволяет заместителю обратиться к реальному

субъекту.

- предоставляет интерфейс, идентичный интерфейсу Subj ect, так что

заместитель всегда может быть подставлен вместо реального субъекта;

- контролирует доступ к реальному субъекту и может отвечать за его

создание и удаление;

- прочие обязанности зависят от вида заместителя:

- удаленный заместитель отвечает за кодирование запроса и его

аргументов и отправление закодированного запроса реальному субъекту в

другом адресном пространстве;

- виртуальный заместитель может кэшировать дополнительную

информацию о реальном субъекте, чтобы отложить его создание.

- защищающий заместитель проверяет, имеет ли вызывающий объект

необходимые для выполнения запроса права;

□ Subject (Graphic) - субъект:

- определяет общий для RealSubject и Proxy интерфейс, так что класс Proxy можно использовать везде, где ожидается RealSubject;

□ RealSubject (Image) - реальный субъект:

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

6)Отношения

Proxy при необходимости переадресует запросы объекту RealSubject. Детали зависят от вида заместителя.

7) Результаты

С помощью паттерна заместитель при доступе к объекту вводится дополнительный уровень косвенности. У этого подхода есть много вариантов в зависимости от вида заместителя:

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

□ виртуальный заместитель может выполнять оптимизацию, например создание объекта но требованию;

□ защищающий заместитель и «умная» ссылка позволяют решать дополнительные задачи при доступе к объекту.

8) Родственные паттерны

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

Принципы SOLID. Принцип SRP

Принципы проектирования облегчают работу программиста, помогая ему строить архитектуру приложения, разбивать функциональность на модули и управлять зависимостями между модулями. Принципы проектирования помогают улучшать дизайн и в результате создавать гибкие масштабируемые приложения, которые кроме всего прочего проще поддерживать. SOLID это аббревиатура пяти основных принципов дизайна классов в объектно-ориентированном проектировании - Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion.

1)SRP – принцип единственной обязанности - на каждый объект должна быть возложена одна единственная обязанность.

2)OCP- принцип закрытости/открытости - программные сущности … должны быть открыты для расширения, но закрыты для изменения.

3)LSP – принцип подстановки Барбары Лисков - объекты в программе могут быть заменены их наследниками без изменения свойств программы.

4)ISP – принцип разделения интерфейса - много специализированных интерфейсов лучше, чем один универсальный.

5)DIP – принцип инверсии зависимостей - зависимости внутри системы строятся на основе абстракций. Модули верхнего уровня не зависят от модулей нижнего уровня. Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

 

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

32.Принципы SOLID. Принцип OCP.

В объектно-ориентированном программировании принцип открытости/закрытости устанавливает следующее положение: «программные сущности (классы, модули, функции и т. п.) должны быть открыты для расширения, но закрыты для изменения»; это означает, что такие сущности могут позволять менять свое поведение без изменения их исходного кода. Это особенно значимо в производственной среде, когда изменения в исходном коде потребуют проведение пересмотра кода, модульного тестирования и других подобных процедур, чтобы получить право на использования его в программном продукте. Код, подчиняющийся данному принципу, не изменяется при расширении и поэтому не требует таких трудозатрат. Термин «принцип открытости/закрытости» имеет два значения. Оба значения используют наследование для решения дилеммы, но цели, способы и результаты — различны.

Принцип открытости/закрытости Мейера.

Бертран Мейер в основном известен как основоположник термина Принцип открытости/закрытости, который появился в 1988 году в его книге Object-Oriented Software Construction. Идея была в том, что однажды разработанная реализация класса в дальнейшем требует только исправления ошибок, а новые или изменённые функции требуют создания нового класса. Этот новый класс может переиспользовать код исходного класса через механизм наследования. Производный подкласс может реализовывать или не реализовывать интерфейс исходного класса.Определение Мейера поддерживает идею реализации наследования. Реализация может быть переиспользована через наследование, но спецификации интерфейса изменяться не должны. Существующая реализация должна быть закрыта для изменений, а новые реализации должны реализовывать существующий интерфейс.

Полиморфизм принципа открытости/закрытости.

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



Поделиться:


Последнее изменение этой страницы: 2016-08-14; просмотров: 353; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

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