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

Принципы (паттерны) GRASP

Лекция



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

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

Принципы (паттерны) GRASP
Key concepts underpinning the GRASP project vision.

Так вот, громадной частью ООП является набор принципов. И тут вроде бы все ясно. Только вот принципов много. И разные авторы выделяют как основные иногда схожие, а иногда и разные принципы, и что удивительно – все правильные.
Моделировать – не сложно. Только проблема в том что мы все таки имеем дело с моделью. А когда объекты (сущности) уже созданы, тогда вступает в игру именно программирование и проектирование. Объекты должны взаимодействовать и при этом модель должна быть гибкой и простой. Вот тут нам и помогают принципы.
GRASP – это набор принципов по версии такого эксперта как Крэг Ларман, который написал о них в своей книге - Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development
Принципы (паттерны) GRASPПринципы (паттерны) GRASP
Кстати, книга есть в переводе на русский. Книга как и книга GoF(Gang of four) заняла свое место в истории и соответственно принципы GRASP, которым посвящена малая часть книги тоже.
Возможно, они не так популярны как скажем принципы SOLID, скорее всего, мне кажется, потому что они определенны более обобщенными. Эти принципы более абстрактные чем шаблоны GoF или SOLID.
Итак принципы GRASP, точнее сказать не принципы, а шаблоны в оригинале. General Responsibility Assignment Software Patterns – это можно перевести так – паттерны распределения ответственности. Суть в том, что это не строгие паттерны как у GoF, это скорее тот смысл, которым мы наделяем объекты. Так что принципы распределения общей ответственности подходит больше чем паттерны. И поэтому название статьи не шаблоны GRASP как было бы идеологически верно, а все таки принципы GRASP.
GRASP выделяет следующие принципы-шаблоны:

  • Information Expert (Информационные эксперт)
  • Creator (Создатель)
  • Controller (Контроллер)
  • Low Coupling (Слабая связанность)
  • High Cohesion (Высокая сцепленность)
  • Pure Fabrication (Чистая выдумка или чистое синтезирование)
  • Indirection (Посредник)
  • Protected Variations (Сокрытие реализации или защищенные изменения)
  • Polymorphism (Полиморфизм)

Теперь давайте рассмотрим каждый из них по порядку.
Information Expert
Информационный эксперт или просто эксперт – это скорее ответственность. Экспертом может быть любой класс. Тут даже дело не в проектировании, а в осведомленности. Зачем нам нужен информационный эксперт? Затем, что если объект владеет всей нужной информацией для какой-то операции или функционала, то значить и этот объект будет выполнять либо делегировать выполнение этой операции.
Итак рассмотрим пример. Есть некая система продаж. И есть класс Sale (продажа). Нам необходимо посчитать общую сумму продаж. Тогда кто будет считать общую сумму по продажам? Конечно же класс – Sales, потому что именно он обладает всей информацией необходимой для этого.
Creator
Creator или Создатель – суть ответственности такого объекта в том, что он создает другие объекты. Сразу напрашивается аналогия с фабриками. Так оно и есть. Фабрики тоже имеют именно ответственность – Создатель.
Но есть ряд моментов, которые должны выполнятся, когда мы наделяем объект ответственность создатель:
1. Создатель содержит или агрегирует создаваемые объекты
2. Создатель использует создаваемые объекты
3. Создатель знает как проинициализировать создаваемый объект
4. Создатель записывает создаваемые объекты (эту штуку я до конце не понял на самом деле)
Controller
Уже где-то слышали, не правда ли? Controller или Контролер – это объект-прослойка между UI логикой и предметной (бизнес) логикой приложения. Создаем контроллер так чтобы все вызовы от UI перенаправлялись именно ему и соответственно все данные UI тоже получает через него.
Напоминает MVC, MVP? Так и есть. Это по сути Presenter из MVP и контроллер из MVC. Разница между MVC и MVP есть, но это касается только направлений вызовов, ну и это тему естественно другой беседы.
Итак, котроллер отвечает на такой вопрос: “Как UI должен взаимодействовать с доменной логикой приложения?” или просто “Как взаимодействовать с системой?”. Это чем то напоминает фасад. Фасад тоже предоставляет облегченный доступ к целой подсистеме объектов. Так и тут контроллер для UI своего рода фасад которые предоставляет доступ к целой подсистеме бизнес логики.
Low Coupling
Тоже известная штука. Low Coupling или Слабая связанность. Если объекты в приложении сильно связанны то любой изменение приводит к изменениям во всех связанных объектах. А это неудобно и порождает баги. Вот по-этому везде пишут что необходимо чтобы код был слабо связан и зависел от абстракций.
Например если наш класс Sale реализует интерфейс ISale и другие объекты зависят именно от ISale, т.е. от абстракции, то когда мы захотим внести изменения касательно Sale – нам нужно будет всего лишь подменить реализацию.
Low Coupling встречается и в SOLID принципах в виде – Dependency Injection. Сейчас можно часто услышать такой принцип. Но суть остается прежней: “Программируйте на основе абстракций (интерфейс, абстрактный класс и т.п.), а не реализаций”.
High Cohesion
High Cohesion или высокая сцепленность – это соотносится к слабой связанности, они идут в паре и одно всегда приводит к другому. Это как инь и янь, всегда вместе. Дело в том что наши классы когда мы их задумываем имеют какую-то одну ответственность (Single resposibility principle), например Sale(продажа) обладает всеми ответственностями которые касаются продаж, например как мы уже говорили вычисление общей суммы – Total. Но давайте представим что мы совершили оплошность и привнесли в Sale еще такую ответственность как Payment (платеж). Что получится? Получится что одни члены класса которые касаются Sale буду между собой достаточно тесно связанны, и также членные класса которые оперируют с Payment между собой будут тесно связаны, но в целом сцепленность класса SaleAndPayment будет низкой, так как по сути мы имеем дело с двумя обособленными частями в одном целом. И резонно будет провести рефакторинг и разделить класс SaleAndPayment на Sale и Payment, которые внутри будут тесно связанны или по другому сцеплены.
Так что высокая сцепленность это как мера того что мы не нарушаем single resposibility principle. Об этом говорит сайт https://intellect.icu . Вернее сказать, выскоая сцепленность получается в результате соблюдения такого приципа из SOLID как single resposibility principle (SRP).
Основной вопрос на который дает ответ высокая сцепленность – “Как поддерживать объекты сфокусированными на одной ответственности, понятными, управляемыми и как побочный эффект иметь слабо связанный код?”. Их разделять. Подробнее это описано в 17 главе книги Лармана.
Pure Fabrication
Pure Fabrication или чистая выдумка или чистое синтезирование. Суть в выдуманном объекте. Такой себе принцип-хак. Но без него никак. Аналогом может быть шаблон Service(сервис) в парадигме DDD.
Иногда, сталкиваемся с таким вопросом: “Какой объект наделить ответственностью, но принципы информационный эксперт, высокая сцепленность не выполняются или не подходят?”. Использовать синтетический класс который обеспечивает высокую сцепленность. Тут без примера точно не разобраться.
Итак – ситуация. Какой класс должен сохранять наш объект Sale в базу данных? Если подчиняется принципу “информационный эксперт”, то Sale, но наделив его такой ответственностью мы получаем слабую сцепленность внутри него. Тогда можно найти выход, создав синтетическую сущность – SaleDao или SaleRepository, которая будет сильно сцеплена внутри и будет иметь единую ответственность – сохранять Sale в базу.
Так как мы выдумали этот объект а не спроектировали с предметной области, то и он подчиняется принципу “чистая выдумка”.
Indirection
Indirection или посредник. Можно столкнутся с таким вопросом: “Как определить ответственность объекта и избежать сильной связанности между объектами, даже если один класс нуждается в функционале (сервисах), который предоставляет другой класс?” Необходимо наделить ответственностью объект посредник.
Например возвратимся опять же MVC. UI логике на самом деле нужен не контроллер, а модель, доменная логика. Но мы не хотим? чтобы UI логика была сильно связанна с моделью, и возможно в UI мы хотим получать данные и работать с разной предметной логикой. А связывать UI слой с бизнес логикой было бы глупо, потому что получим код который будет сложный для изменений и поддержки. Выход – вводим контроллер как посредника между View и Model.
Так что распределяйте ответственности своим объектам ответственно (с умом).
Protected Variations
Protected Variations или сокрытие реализации или защищенные изменения. Как спроектировать объекты, чтобы изменения в объекте или объекта не затрагивали других? Как избежать ситуации когда меняя код объекта придется вносить изменения в множество других объектов системы?
Кажется мы такое обсуждали уже. И пришли к выводу что нужно использовать low coupling или dependency injection. Именно! Но суть в принципа немного в другом. Суть в том чтобы определить “точки изменений” и зафиксировать их в абстракции (интерфейсе). “Точки изменений” – не что иное как наши объекты, которые могут меняться.
То есть суть в принципа, чтобы определить места в системе, где поведение может изменится и выделить абстракцию, на основе которой и будет происходить дальнейшее программирование с использованием этого объекта.
Все это делается для того чтобы обеспечить устойчивость интерфейса. Если будет много изменений связанных с объектов, он, в таком ключе, считается не устойчивым и тогда нужно выносить его в абстракцию от которой будем зависеть, либо распределять обязанности и ответственность в код иным образом
Polymorphism
Polymorphism или полиморфизм. Тоже знакомо, не так ли? Так вот это об том же полиморфизме, который мы знаем из ООП. Если заметить то достаточно много паттернов GoF, да и вообще паттернов, построено на полиморфизме. Что он дает?Он дает возможность трактовать однообразно разные объекты с одинаковым интерфейсом (спецификацией). Давайте вспомним такие паттерны как Strategy, Chain of Resposibility, Command… – их много. И все по своей суть основываются на полиморфизме.
Полиморфизм решает проблему обработки альтернативных вариантов поведения на основе типа. Тут яркий пример это шаблон GoF – Strategy (Стратегия).
Например, для реализации гибкого функционала для шифрования можно определить интерфейс IEncryptionAlgorithm с методом Encrypt, и объект создатель, который вернет IEncryptionAlgorithm, создав внутри себя актуальную реализацию этого интерфейса.


Явно или неясно, пользуясь другими принципами или шаблонами – мы тоже часто используем принципы или шаблоны GRASP при разработке и проектировании. Многие принципы пересекаются, просто возможно разные авторы по разному смещают акценты, но на удивление все принципы и шаблоны верны – и SOLID, и GRASP и классические GoF паттерны и многие другие. И все их следует использовать с умом и балансировать ними применяя совместно с какими-то хаками под свою систему, что позволяет разрабатывать действительно красивые, устойчивые и гибкие архитектуры и приложения.
Принципы GRASP хоть и упоминаются реже других все же занимают свое место и играют важную роль именно в распределении обязанностей между объектами и заставляют нас думать еще и в таком ключе, а не просто подгонять шаблоны как кирпичи разной формы чтобы выстроить пазл архитектуры.
Принципы GRASP не создают четкую структуру, которой мы должны следовать в коде. Это больше распределение ролей и ответственностей между объектами, а также свойства, которыми эти объекты должны обладать для того чтобы исполнять свои р

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

Принципы (паттерны) GRASP

GRASP   Craig Larman Книга Applying UML and Patterns, 3ed. GRASP stands for General Responsibility Assignment Software Patterns.

Полный список шаблонов GRASP

  • Information
  • Expert
  • Creator
  • Controller
  • Low Coupling
  • High Cohesion
  • Polymorphism
  • Pure
  • Fabrication
  • Indirection
  • Protected Variations

Шаблон информационный эксперт (Information Expert)- GRASP Проблема

Решение

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

Информационным экспертом может быть не один класс, а несколько.

. Эксперт.

Пример

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

Эксперт. Диаграмма классов

Создатель экземпляров класса (Creator) - GRASP

Проблема

Решение

"Кто" должен отвечать за создание экземпляров класса. Назначить классу В обязанность создавать объекты другого класса А Рекомендации Логично использовать паттерн если класс В содержит, агрегирует, активно использует и т.п. объекты класса А.

Creator. Пример.

необходимо определить, какой объект должен отвечать за создание экземпляра "ТоварПродажа". Логично, чтобы это был объект "Продажа", поскольку он содержит (агрегирует) несколько объектов "ТоварПродажа".

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

. Creator. Критика

Преимущества

Использование этого паттерна не повышает связанности, поскольку созданный класс, как правило, виден только для класса - создателя

. Недостатки

Если процедура создания объекта достаточно сложная (например выполняется на основе некоего внешнего условия), логично использовать паттерн "Абстрактная Фабрика",, то есть, делегировать обязанность создания объектов специальному классу.

Контроллер (Controller) GRAS

Проблема

Решение

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

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

Controller. Критика

Преимущества

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

Недостатки

Контроллер может оказаться перегружен.

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

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

Пример нарушения


Самым ярким примером нарушения этого принципа, с моей точки зрения, является циклическая зависимость (да-да, то, за что обычно отрывают руки на code review):

Проблема

Обеспечить низкую связанность при создании экземпляра класса и связывании его с другим классом.

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

Низкая связанность.

однако иногда может потребоваться высокая связанность(tight coupling)

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

Высокое зацепление (High Cohesion) - GRASP


Если возвести Low Coupling в абсолют, то достаточно быстро можно прийти к тому, чтобы разместить всю функциональность в одном единственном классе. В таком случае связей не будет вообще, но все при этом понимают, что что-то тут явно не так, ведь в этот класс попадет совершенно несвязанная между собой бизнес — логика. Принцип High Cohesion говорит нам следующее: классы должны содержать связанную бизнес — логику.

Проблема

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

Решение

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

Высокое зацепление. Критика

Преимущества

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

Недостатки

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

Low Coupling и High Cohesion представляют из себя два связанных между собой паттерна, рассматривать которые имеет смысл только вместе. Их суть можно объединить следующим образом: система должна состоять и слабо связанных классов, которые содержать связанную бизнес — логику. Соблюдение этих принципов позволяет удобно переиспользовать созданные классы, не теряя понимания об их зоне ответственности.

Деструктивная развязка (decoupling)– самый интересный случай. Это может происходить, когда программист пытается так сильно развязать кодовую базу, что код полностью теряет фокус'

Принципы (паттерны) GRASP

зацепление , зависимость , связанность , связность ,

Полиморфизм (Polymorphism) - GRASP

Проблема

Как обрабатывать альтернативные варианты поведения на основе типа? Как заменять подключаемые компоненты системы?

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

Полиморфизм. Пример

Полиморфизм. Критика

Преимущества

Впоследствии легко расширять и модернизировать систему.

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

Искусственный (Pure Fabrication) - GRASP

Проблема

Какой класс должен обеспечивать реализацию паттернов "Высокое зацепление", и "Низкая связанность"?

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

Искусственный. Пример

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

Искусственный. Пример Решением данной проблемы будет создание нового класса "ПостоянноеХранилище", ответственного за сохранение объектов некоторого вида в базе данных.

Искуственный. Критика

Преимущества

Класс "ПостоянноеХранилище" будет обладать низкой степенью связывания и высокой степенью зацепления.

Недостатки

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

Перенаправление (Indirection) - GRASP

Проблема

Решение

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

Пример

См. пример к паттерну "Искусственный". Класс "Хранилище" выступает в роли промежуточного звена между классом "Продажа" и базой данных.

Устойчивый к изменениям (Protected Variations) GRASP

Проблема

Как спроектировать систему так, чтобы изменение одних ее элементов не влияло на другие?

Решение

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

Устойчивый к изменениям. Пример

Вау!! 😲 Ты еще не читал? Это зря!

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

создано: 2019-02-15
обновлено: 2021-11-18
132265



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


Поделиться:

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

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

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

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



Комментарии


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

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

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