В программной инженерии шаблон серванта определяет объект, используемый для предоставления некоторой функциональности группе классов без определения этой функциональности в каждом из них. Сервант — это класс, экземпляр которого (или даже просто класс) предоставляет методы , которые заботятся о желаемой услуге, в то время как объекты, для которых (или с которыми) сервант что-то делает, принимаются в качестве параметров .
Servant используется для предоставления некоторого поведения группе классов. Вместо определения этого поведения в каждом классе — или когда мы не можем выделить это поведение в общем родительском классе — оно определяется один раз в Servant.
Например: у нас есть несколько классов, представляющих геометрические объекты (прямоугольник, эллипс и треугольник). Мы можем нарисовать эти объекты на некотором холсте. Когда нам нужно предоставить метод «перемещения» для этих объектов, мы можем реализовать этот метод в каждом классе или определить интерфейс, который они реализуют, а затем предложить функциональность «перемещения» в серванте. Интерфейс определяется для того, чтобы обслуживаемые классы имели методы, необходимые серванту для обеспечения желаемого поведения. Если мы продолжим наш пример, мы определим интерфейс «Movable», указав, что каждый класс, реализующий этот интерфейс, должен реализовать методы «getPosition» и «setPosition». Первый метод получает положение объекта на холсте, а второй устанавливает положение объекта и рисует его на холсте. Затем мы определяем класс серванта «MoveServant», который имеет два метода «moveTo(Movable movedObject, Position where)» и moveBy(Movable movedObject, int dx, int dy). Теперь класс Servant можно использовать для перемещения каждого объекта, реализующего Movable. Таким образом, «перемещающийся» код появляется только в одном классе, который соблюдает правило «разделения ответственности».
Существует два способа реализации этого шаблона проектирования:
Этот простой пример 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 очень похожи, и реализации их часто практически одинаковы. Разница между ними заключается в подходе к проблеме.
Хотя шаблоны проектирования Command и Servant похожи, это не значит, что так всегда. Существует ряд ситуаций, в которых использование шаблона проектирования Command не связано с шаблоном проектирования Servant. В таких ситуациях нам обычно нужно передать вызываемым методам только ссылку на другой метод, который понадобится ему для достижения своей цели. Поскольку во многих языках мы не можем передавать ссылки на методы, нам нужно передать объект, реализующий интерфейс, который объявляет сигнатуру переданного метода.
Пециновский, Рудольф; Ярмила Павличкова; Любош Павличек (июнь 2006 г.). Давайте сначала изменим подход «Сначала объекты» на шаблоны проектирования (PDF) . Одиннадцатая ежегодная конференция по инновациям и технологиям в области компьютерных наук, Болонский университет.