Слуга (шаблон проектирования) - Servant (design pattern)

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

Описание и простой пример

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

Например: у нас есть несколько классов, представляющих геометрические объекты (прямоугольник, эллипс и треугольник). Мы можем нарисовать эти объекты на каком-нибудь холсте. Когда нам нужно предоставить метод «перемещения» для этих объектов, мы могли бы реализовать этот метод в каждом классе или определить интерфейс, который они реализуют, а затем предложить функциональность «перемещения» в серванте. Интерфейс определен, чтобы гарантировать, что у обслуживаемых классов есть методы, необходимые серванту для обеспечения желаемого поведения. Если мы продолжим наш пример, мы определим интерфейс «Movable», указав, что каждый класс, реализующий этот интерфейс, должен реализовать методы «getPosition» и «setPosition». Первый метод получает положение объекта на холсте, а второй устанавливает положение объекта и рисует его на холсте. Затем мы определяем класс слуги «MoveServant», который имеет два метода «moveTo (Movable moveObject, Position where)» и moveBy (Movable moveObject, int dx, int dy). Класс Servant теперь можно использовать для перемещения каждого объекта, реализующего Movable. Таким образом, «движущийся» код появляется только в одном классе, который соблюдает правило «разделения проблем».

Два способа реализации

Есть два способа реализовать этот шаблон проектирования.

Рисунок 1. Пользователь использует сервант для достижения некоторой функциональности и передает обслуживаемые объекты в качестве параметров.
  1. Пользователь знает слугу (и в этом случае ему не нужно знать обслуживаемые классы) и отправляет сообщения со своими запросами экземплярам серванта, передавая обслуживаемые объекты в качестве параметров.
  2. Обслуживаемые классы (геометрические объекты из нашего примера) не знают о серванте, но они реализуют интерфейс IServiced. Класс пользователя просто вызывает метод слуги и передает обслуживаемые объекты в качестве параметров. Эта ситуация показана на рисунке 1.
Рисунок 2: Пользователь запрашивает операции у обслуживаемых экземпляров, которые затем просят слугу сделать это за них.
  1. Обслуживаемые экземпляры знают слугу, и пользователь отправляет им сообщения со своими запросами (в этом случае ей не обязательно знать слугу). Обслуживаемые экземпляры затем отправляют сообщения экземплярам серванта с просьбой об обслуживании.
  2. На рисунке 2 показана противоположная ситуация, когда пользователь не знает о классе серванта и вызывает непосредственно обслуживаемые классы. Обслуживаемые классы затем запрашивают у слуги желаемую функциональность.

Как реализовать Servant

  1. Проанализируйте, о каком поведении слуге следует позаботиться. Укажите, какие методы будет определять слуга, и что этим методам потребуется из обслуживаемого параметра. Другими словами, какой обслуживаемый экземпляр должен предоставить, чтобы методы слуг могли достичь своих целей.
  2. Проанализируйте, какими способностями должны обладать обслуживаемые классы, чтобы их можно было должным образом обслуживать.
  3. Мы определяем интерфейс, который будет обеспечивать реализацию объявленных методов.
  4. Определите интерфейс, определяющий запрошенное поведение обслуживаемых объектов. Если какой-то экземпляр хочет, чтобы его обслужил слуга, он должен реализовать этот интерфейс.
  5. Определите (или приобретите каким-либо образом) указанного слугу (его класс).
  6. Реализуйте определенный интерфейс с обслуживаемыми классами.

пример

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

// Класс Servant, предлагающий свои функции классам, реализующим// Подвижный интерфейсобщественный класс MoveServant {	// Метод, который переместит класс реализации Movable в позицию, где	общественный пустота moveTo(Подвижный обслуживается, Должность где) {		// Сделаем еще кое-что, чтобы он двигался плавно и красиво, это		// место для предложения функциональности		обслуживается.setPosition(где);	}	// Метод, который переместит класс реализации Movable на dx и dy	общественный пустота moveBy(Подвижный обслуживается, int dx, int dy) {		// это место, где можно предложить функциональность		dx += обслуживается.getPosition().xPosition;		dy += обслуживается.getPosition().yPosition;		обслуживается.setPosition(новый Должность(dx, dy));	}}// Интерфейс, определяющий, какие обслуживаемые классы необходимо реализовать, чтобы// обслуживается слугой.общественный интерфейс Подвижный {	общественный пустота setPosition(Должность п);	общественный Должность getPosition();}// Один из геометрических классовобщественный класс Треугольник орудия Подвижный {	// Положение геометрического объекта на некотором холсте	частный Должность п;        // Метод, устанавливающий положение геометрического объекта	общественный пустота setPosition(Должность п) {		этот.п = п;	}	// Метод, возвращающий положение геометрического объекта	общественный Должность getPosition() {		вернуть этот.п;	}}// Один из геометрических классовобщественный класс Эллипс орудия Подвижный {	// Положение геометрического объекта на некотором холсте	частный Должность п;	// Метод, устанавливающий положение геометрического объекта	общественный пустота setPosition(Должность п) {		этот.п = п;	}	// Метод, возвращающий положение геометрического объекта	общественный Должность getPosition() {		вернуть этот.п;	}}// Один из геометрических классовобщественный класс Прямоугольник орудия Подвижный {	// Положение геометрического объекта на некотором холсте	частный Должность п;	// Метод, устанавливающий положение геометрического объекта	общественный пустота setPosition(Должность п) {		этот.п = п;	}	// Метод, возвращающий положение геометрического объекта	общественный Должность getPosition() {		вернуть этот.п;	}}// Просто очень простой контейнерный класс для позиции.общественный класс Должность {	общественный int xPosition;	общественный int yPosition;	общественный Должность(int dx, int dy) {		xPosition = dx;		yPosition = dy;	}}

Подобный шаблон проектирования: Команда

Шаблоны проектирования Команда и Servant очень похожи, и их реализации часто практически одинаковы. Разница между ними - подход к проблеме.

  • Для паттерна «Слуга» у нас есть несколько объектов, которым мы хотим предложить некоторые функции. Мы создаем класс, экземпляры которого предлагают эту функциональность и который определяет интерфейс, который должны реализовывать обслуживаемые объекты. Обслуживаемые экземпляры затем передаются серванту в качестве параметров.
  • Для шаблона Command у нас есть некоторые объекты, которые мы хотим изменить с помощью некоторых функций. Итак, мы определяем интерфейс, команды которого должны быть реализованы. Экземпляры этих команд затем передаются исходным объектам в качестве параметров их методов.

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

Смотрите также

Ресурсы

Печиновский, Рудольф; Ярмила Павличкова; Любош Павличек (июнь 2006 г.). Давайте сначала изменим подход к объектам в шаблоны проектирования (PDF). Одиннадцатая ежегодная конференция по инновациям и технологиям в образовании в области компьютерных наук, Болонский университет.