Слуга (шаблон дизайна)

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

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

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

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

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

Существует два способа реализации этого шаблона проектирования:

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

Пример

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

// Класс Servant, предлагающий свою функциональность классам, реализующим // Movable Interface public class MoveServant { // Метод, который переместит реализующий класс Movable в позицию, где public void moveTo ( Movable serviced , Position where ) { // Сделайте что-нибудь еще, чтобы обеспечить его плавное и красивое перемещение, это // место, где можно предложить функциональность serviced . setPosition ( where ); }         // Метод, который переместит реализующий класс Movable по dx и dy public void moveBy ( Movable serviced , int dx , int dy ) { // это место, где можно предложить функциональность dx += serviced.getPosition ( ). xPosition ; dy + = serviced.getPosition ( ). yPosition ; serviced.setPosition ( new Position ( dx , dy ) ) ; } }              // Интерфейс, указывающий, какие обслуживаемые классы необходимо реализовать, чтобы // они обслуживались сервантом. public interface Movable { public void setPosition ( Position p );      публичная позиция getPosition (); }  // Один из геометрических классов public class Triangle implements Movable { // Положение геометрического объекта на некотором холсте private Position p ;        // Метод, который устанавливает положение геометрического объекта public void setPosition ( Position p ) { this . p = p ; }      // Метод, возвращающий позицию геометрического объекта public Position getPosition () { return this . p ; } }    // Один из геометрических классов public class Ellipse implements Movable { // Положение геометрического объекта на некотором холсте private Position p ;       // Метод, который устанавливает положение геометрического объекта public void setPosition ( Position p ) { this . p = p ; }      // Метод, возвращающий позицию геометрического объекта public Position getPosition () { return this . p ; } }    // Один из геометрических классов public class Rectangle implements Movable { // Положение геометрического объекта на некотором холсте private Position p ;       // Метод, который устанавливает положение геометрического объекта public void setPosition ( Position p ) { this . p = p ; }      // Метод, возвращающий позицию геометрического объекта public Position getPosition () { return this . p ; } }    // Просто очень простой класс-контейнер для позиции. public class Position { public int xPosition ; public int yPosition ;       публичная позиция ( int dx , int dy ) { xPosition = dx ; yPosition = dy ; } }         

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

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

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

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

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

Ссылки

Ресурсы

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

Взято с "https://en.wikipedia.org/w/index.php?title=Servant_(design_pattern)&oldid=1243542283"