En ingeniería de software , el patrón de servidor define un objeto utilizado para ofrecer alguna funcionalidad a un grupo de clases sin definir esa funcionalidad en cada una de ellas. Un Servant es una clase cuya instancia (o incluso solo clase) proporciona métodos que se encargan de un servicio deseado, mientras que los objetos para los cuales (o con quién) el sirviente hace algo, se toman como parámetros .
Descripción y ejemplo sencillo
Sirviente se usa para proporcionar algún comportamiento a un grupo de clases. En lugar de definir ese comportamiento en cada clase, o cuando no podemos descartar este comportamiento en la clase principal común, se define una vez en el Servant.
Por ejemplo: tenemos algunas clases que representan objetos geométricos (rectángulo, elipse y triángulo). Podemos dibujar estos objetos en algún lienzo. Cuando necesitemos proporcionar un método de "mover" para estos objetos, podríamos implementar este método en cada clase, o podemos definir una interfaz que ellos implementen y luego ofrecer la funcionalidad de "mover" en un servidor. Se define una interfaz para asegurar que las clases atendidas tengan métodos que el sirviente necesita para proporcionar el comportamiento deseado. Si continuamos con nuestro ejemplo, definimos una Interfaz "Móvil" especificando que cada clase que implementa esta interfaz necesita implementar el método "getPosition" y "setPosition". El primer método obtiene la posición de un objeto en un lienzo y el segundo establece la posición de un objeto y lo dibuja en un lienzo. Luego definimos una clase de servidor "MoveServant", que tiene dos métodos "moveTo (Movable movedObject, Position where)" y moveBy (Movable movedObject, int dx, int dy). La clase Servant ahora se puede usar para mover todos los objetos que implementen Movable. Por lo tanto, el código "en movimiento" aparece en una sola clase que respeta la regla de "Separación de preocupaciones".
Dos formas de implementación
Hay dos formas de implementar este patrón de diseño.
- El usuario conoce al sirviente (en cuyo caso no necesita conocer las clases atendidas) y envía mensajes con sus solicitudes a las instancias del sirviente, pasando los objetos atendidos como parámetros.
- Las clases atendidas (objetos geométricos de nuestro ejemplo) no conocen el servidor, pero implementan la interfaz "IServiced". La clase de usuario simplemente llama al método de sirviente y pasa los objetos atendidos como parámetros. Esta situación se muestra en la figura 1.
- Las instancias atendidas conocen al sirviente y el usuario les envía mensajes con sus solicitudes (en cuyo caso no tiene que conocer al sirviente). Las instancias atendidas luego envían mensajes a las instancias de sirviente, solicitando el servicio.
- En la figura 2 se muestra la situación opuesta, donde el usuario no conoce la clase de servidor y llama directamente a las clases atendidas. A continuación, las clases atendidas le piden a los propios servidores que logren la funcionalidad deseada.
Cómo implementar Servant
- Analiza qué comportamiento debe cuidar el sirviente. Indique qué métodos definirá el sirviente y qué necesitarán estos métodos del parámetro servido. En otras palabras, qué debe proporcionar la instancia con servicio, para que los métodos de los servidores puedan lograr sus objetivos.
- Analice qué habilidades deben tener las clases atendidas, para que puedan ser atendidas adecuadamente.
- Definimos una interfaz, que hará cumplir la implementación de los métodos declarados.
- Defina una interfaz que especifique el comportamiento solicitado de los objetos atendidos. Si alguna instancia quiere ser servida por un servidor, debe implementar esta interfaz.
- Definir (o adquirir de alguna manera) un sirviente específico (su clase).
- Implementar una interfaz definida con clases atendidas.
Ejemplo
Este sencillo ejemplo de Java muestra la situación descrita anteriormente. Este ejemplo es solo ilustrativo y no ofrecerá ningún dibujo real de objetos geométricos, ni especificación de cómo se ven.
// Clase Servant, que ofrece su funcionalidad a las clases que implementan // Movable Interface public class MoveServant { // Método, que moverá la clase de implementación Movable a la posición donde public void moveTo ( Movable serviced , Position where ) { // Hacer algunas otras cosas para asegúrese de que se mueva suave y agradablemente, este es // el lugar para ofrecer la funcionalidad reparada . setPosition ( donde ); }// Método, que moverá la clase de implementación Movable por dx y dy public void moveBy ( Movable serviced , int dx , int dy ) { // este es el lugar para ofrecer la funcionalidad dx + = serviced . getPosition (). xPosition ; dy + = reparado . getPosition (). yPosition ; atendido . setPosition ( nueva posición ( dx , dy )); } }// Interfaz que especifica qué clases con servicio necesitan implementar, // para ser servidas por el sirviente. interfaz pública Movable { public void setPosition ( Posición p ); pública Posición getPosition (); }// Una de las clases geométricas public class Triangle implementa Movable { // Posición del objeto geométrico en algún lienzo private Position p ; // Método, que establece la posición del objeto geométrico public void setPosition ( Position p ) { this . p = p ; }// Método, que devuelve la posición del objeto geométrico public Position getPosition () { return this . p ; } }// Una de las clases geométricas public class Ellipse implementa Movable { // Posición del objeto geométrico en algún lienzo private Position p ;// Método, que establece la posición del objeto geométrico public void setPosition ( Position p ) { this . p = p ; }// Método, que devuelve la posición del objeto geométrico public Position getPosition () { return this . p ; } }// Una de las clases geométricas public class Rectangle implementa Movable { // Posición del objeto geométrico en algún lienzo private Position p ;// Método, que establece la posición del objeto geométrico public void setPosition ( Position p ) { this . p = p ; }// Método, que devuelve la posición del objeto geométrico public Position getPosition () { return this . p ; } }// Solo una clase de contenedor muy simple para la posición. Posición de la clase pública { public int xPosition ; public int yPosition ; Posición pública ( int dx , int dy ) { xPosition = dx ; yPosition = dy ; } }
Patrón de diseño similar: comando
Los patrones de diseño Command y Servant son muy similares y sus implementaciones a menudo son prácticamente las mismas. La diferencia entre ellos es el enfoque del problema.
- Para el patrón Servant tenemos algunos objetos a los que queremos ofrecer alguna funcionalidad. Creamos una clase cuyas instancias ofrecen esa funcionalidad y que define una interfaz que los objetos atendidos deben implementar. A continuación, las instancias con servicio se pasan como parámetros al sirviente.
- Para el patrón Command tenemos algunos objetos que queremos modificar con alguna funcionalidad. Entonces, definimos una interfaz que ordena qué funcionalidad deseada debe implementarse. Luego, las instancias de esos comandos se pasan a los objetos originales como parámetros de sus métodos.
Aunque los patrones de diseño Command y Servant son similares, no significa que siempre sea así. Hay una serie de situaciones en las que el uso del patrón de diseño Command no se relaciona con el patrón de diseño Servant. En estas situaciones, generalmente necesitamos pasar a los métodos llamados solo una referencia a otro método, que necesitará para lograr su objetivo. Dado que no podemos pasar referencias a métodos en muchos lenguajes, tenemos que pasar un objeto que implemente una interfaz que declare la firma del método pasado.
Ver también
Recursos
Pecinovský, Rudolf; Jarmila Pavlíčková; Luboš Pavlíček (junio de 2006). Modifiquemos primero el enfoque de objetos en patrones de diseño primero (PDF) . XI Conferencia Anual sobre Innovación y Tecnología en la Educación en Informática, Universidad de Bolonia .