Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ПРИС_шпоры.doc
Скачиваний:
3
Добавлен:
01.03.2025
Размер:
3 Мб
Скачать
☆

60.Grasp: принцип Controller.

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

Системное событие (system event) — это событие, генерируемое внешним исполнителем в процессе его взаимодействия с системой. Системные события связаны с системными операциями (system operation), т. е. операциями, выполняемыми системой в ответ на системные события.

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

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

Решение. Делегировать обязанности по обработке системных сообщений классу, удовлетворяющему одному из следующих условий:

  • класс представляет всю систему в целом, устройство или подсистему (внешний контроллер);

  • класс представляет сценарий некоторого прецедента, в рамках которого выполняется обработка всех системных событий, и обычно называется <Прецедент>Наndlеr, <Прецедент>Coordinator или <Прецедент>Session (контроллер прецедента или контроллер сеанса).

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

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

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

Рис. 11. Некоторые системные операции для приложения NextGen (на

этом рисунке вся система представлена в виде класса, что

допустимо, а иногда и полезно)

Пример. В приложении NextGen существует несколько системных операций (рис. 11).

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

Какой класс должен выступать в роли контроллера для системных событий типа enterItem или makeNewReturn (рис. 12)?

Рис. 12. Кто является контроллером для события enterItem?

Согласно шаблону Controller, возможны следующие варианты:

  • класс, представляющий всю систему в целом, устройство или подсистему (Register, POSSystem);

  • класс, представляющий получателя или искусственный обработчик всех системных событий некоторого сценария прецедента (ProcessSaleSession / ProcessSaleHandler или ProcessReturnsSession / ProcessReturnsHandler).

Замечание. В предметной области POS-систем объект Register (который также называют терминалом) представляет собой специализированное утройство с соответствующим программным обеспечением.

В терминах диаграммы взаимодействий должен использоваться один из вариантов, представленных на рис. 13.

Рис. 13. Варианты контроллеров

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

Системные операции, идентифицированные в процессе анализа поведения системы, на этапе проектирования присваиваются одному или нескольким классам контроллеров (рис. 14).

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

Во всех случаях при использовании объектно-ориентированного подхода для обработки внешних событий применяются контроллеры. Шаблон Controller обеспечивает наиболее типичные проектные решения для этого случая. Как видно из рис. 12, контроллер — это своеобразный вид интерфейса между уровнями предметной области и графического представления.

Рис. 14. Распределение системных операций

Чтобы обеспечить возможность поддержки информации о состоянии прецедента, для обработки всех системных событий в рамках одного прецедента должен использоваться один и тот же класс контроллера. Такая информация может понадобиться, например, для идентификации момента нарушения последовательности системных событий (например, выполнение операции makePayment перед выполнением операции endSale). Для различных прецедентов можно использовать разные контроллеры.

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

Первым типом контроллеров является внешний контроллер (façade controller), представляющий всю «систему», устройство или подсистему. Основная идея сводится к выбору некоторого класса, имя которого охватывает все слои приложения. Этот класс обеспечивает главную точку вызова всех служб из интерфейса пользователя и обращения к остальным слоям. Этот класс может представлять физический объект: например систему (Register), телекоммуникационный переключатель (TelecommSwitch, Phone) или устройство (Robot); всю программную часть системы: например POSSystem, или любые другие понятия, выбранные разработчиком для представления системы в целом.

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

Если применяется контроллер прецедента (use case controller), то для каждого прецедента должен существовать отдельный контроллер. Заметим, что это не объект из предметной области, а искусственная конструкция, поддерживающая жизнедеятельность системы (ср. с шаблоном Pure Fabrication). Например, если в системе NextGen используются прецеденты «Оформление продажи» и «Возврат товара», то в ней могут быть реализованы классы ProcessSaleHandler (Обработчик продажи) и ProcessReturnsHandler (Обработчик возвратов).

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

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

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

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

  • Контроль состояния прецедента. Иногда необходимо удостовериться, что системные операции выполняются в некоторой определенной последовательности. Например, необходимо гарантировать, чтобы операция makePayment выполнялась только после операции endSale, для чего необходимо накапливать информацию о последовательности событий. Для этой цели удобноиспользовать контроллер, особенно контроллер прецедента.

Проблемы и решения

Плохо спроектированный класс контроллера имеет низкую степень зацепления: он выполняет слишком много обязанностей и является несфокусированным. Такой контроллер называется раздутым (bloated controller). Признаки раздутого контроллера таковы:

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

  • контроллер сам выполняет все задачи, не делегируя обязанности другим классам. Обычно это приводит к нарушению основных принципов шаблонов Information Expert и High Cohesion;

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

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

1) Добавить несколько контроллеров. Помимо внешних контроллеров, можно использовать контроллеры прецедентов. Например, в системе, имеющей много системных событий (скажем, в системе резервирования авиабилетов), можно использовать следующие контроллеры: MakeReservationHandler (обработчик события резервирования), ManageSchedulesHandler (менеджер расписания), ManageFaresHandler (менеджер тарифов).

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

123