Patrón de localizador de servicios

El patrón de localizador de servicios (Service Locator Pattern) se utiliza cuando queremos usar JNDI para consultar y localizar diversos servicios. Teniendo en cuenta que buscar JNDI para un servicio tiene un costo muy alto, el patrón de localizador de servicios aprovecha al máximo la tecnología de caché. En la primera solicitud de un servicio, el localizador de servicios busca el servicio en JNDI y almacena en caché el objeto de servicio. Cuando se solicita nuevamente el mismo servicio, el localizador de servicios lo busca en su caché, lo que puede mejorar en gran medida el rendimiento de la aplicación. A continuación se presentan las entidades de este patrón de diseño.

  • Servicio (Service)- El servicio que realmente procesa las solicitudes. La referencia a este servicio se puede encontrar en el servidor JNDI.
  • Contexto / Contexto inicial- El contexto JNDI contiene la referencia al servicio que se va a buscar.
  • Localizador de servicios (Service Locator)- El localizador de servicios es el punto único de contacto para obtener servicios mediante la búsqueda en JNDI y el almacenamiento en caché.
  • Caché (Cache)- La caché almacena las referencias de los servicios para poder reutilizarlas.
  • Cliente (Client)- El cliente es el objeto que llama a los servicios a través de ServiceLocator.

Resumen

Intención

Se utiliza para proporcionar un punto de acceso centralizado a servicios en la aplicación, con el fin de obtener diversos servicios o recursos.

Problema principal que resuelve

  • Resuelve el problema de evitar la codificación fija (hardcode) de la lógica de acceso a servicios cuando la aplicación necesita acceder a diversos servicios o recursos.

Escenarios de uso

  • Cuando la aplicación necesita acceder a múltiples servicios o recursos externos y se desea gestionar esta lógica de acceso de forma centralizada.

Forma de implementación

  • Interfaz del localizador de servicios: define el método para obtener servicios.
  • Implementación del localizador de servicios: implementa la interfaz del localizador de servicios y encapsula la lógica de búsqueda y acceso a servicios.
  • Interfaz de servicio: define la interfaz o contrato del servicio.
  • Servicio concreto: implementa la interfaz de servicio y proporciona las funcionalidades específicas del servicio.

Código clave

  • Localizador de servicios: contiene la lógica para buscar y devolver la instancia del servicio solicitado.
  • Interfaz de servicio: define la representación abstracta del servicio.

Ejemplos de aplicación

  • Aplicaciones empresariales: la aplicación utiliza el localizador de servicios para acceder a servicios de base de datos, servicios de cola de mensajes, etc.

Ventajas

  1. Desacoplar el acceso a servicios: separa la lógica de acceso a servicios de la lógica de negocio que utiliza los servicios.
  2. Gestión centralizada: el punto de acceso a los servicios se gestiona de forma centralizada, lo que facilita el mantenimiento y la expansión.
  3. Flexibilidad: es fácil añadir, modificar o reemplazar servicios.

Desventajas

  • Problemas de rendimiento: el localizador de servicios puede introducir una sobrecarga de rendimiento, especialmente cuando se realiza una búsqueda en cada solicitud de servicio.
  • Uso excesivo: puede provocar un abuso del patrón de diseño, ocultando así la estructura del sistema.

Recomendaciones de uso

  • Cuando la aplicación necesite acceder a múltiples servicios de manera flexible y mantenible, considere utilizar el patrón de localizador de servicios.

Precauciones

  • Evite una dependencia excesiva del localizador de servicios, ya que puede ocultar las dependencias del sistema, dificultando la depuración y la optimización.

Roles principales incluidos

  1. Interfaz del localizador de servicios (Service Locator Interface):

    • Define el método para obtener servicios.
  2. Implementación del localizador de servicios (Service Locator Implementation):

    • Implementa la interfaz del localizador de servicios y encapsula la lógica de búsqueda y acceso a los servicios.
  3. Interfaz de servicio (Service Interface):

    • Define la representación abstracta del servicio.
  4. Servicio concreto (Concrete Service):

    • Implementa la interfaz de servicio y proporciona las funcionalidades específicas del servicio.
  5. Cliente (Client):

    • Utiliza el localizador de servicios para acceder a los servicios necesarios.

El patrón de localizador de servicios, al proporcionar un punto de acceso centralizado a los servicios, ayuda a simplificar la lógica de acceso a los servicios y mejora la flexibilidad y el mantenimiento de la aplicación.


<

Implementación

CrearemosServiceLocator、InitialContext、Cache、Servicevarios objetos que representan entidades.Service1yService2Representa el servicio de entidad.

ServiceLocatorPatternDemoLa clase aquí actúa como un cliente y utilizaráServiceLocatorpara demostrar el patrón de diseño de localizador de servicios.

服务定位器模式的 UML 图

Paso 1

Crear la interfaz de servicio Service.

Service.java

public interface Service { public String getName(); public void execute(); }

Paso 2

Crear el servicio de entidad.

Service1.java

public class Service1 implements Service { public void execute(){ System.out.println("Executing Service1"); } @Override public String getName() { return "Service1"; } }

Service2.java

public class Service2 implements Service { public void execute(){ System.out.println("Executing Service2"); } @Override public String getName() { return "Service2"; } }

Paso 3

Crear InitialContext para la consulta JNDI.

InitialContext.java

public class InitialContext { public Object lookup(String jndiName){ if(jndiName.equalsIgnoreCase("SERVICE1")){ System.out.println("Looking up and creating a new Service1 object"); return new Service1(); }else if (jndiName.equalsIgnoreCase("SERVICE2")){ System.out.println("Looking up and creating a new Service2 object"); return new Service2(); } return null; } }

Paso 4

Crear la caché Cache.

Cache.java

import java.util.ArrayList; import java.util.List; public class Cache { private List<Service> services; public Cache(){ services = new ArrayList<Service>(); } public Service getService(String serviceName){ for (Service service : services) { if(service.getName().equalsIgnoreCase(serviceName)){ System.out.println("Returning cached "+serviceName+" object"); return service; } } return null; } public void addService(Service newService){ boolean exists = false; for (Service service : services) { if(service.getName().equalsIgnoreCase(newService.getName())){ exists = true; } } if(!exists){ services.add(newService); } } }

Paso 5

Crear el localizador de servicios.

ServiceLocator.java

public class ServiceLocator { private static Cache cache; static { cache = new Cache(); } public static Service getService(String jndiName){ Service service = cache.getService(jndiName); if(service != null){ return service; } InitialContext context = new InitialContext(); Service service1 = (Service)context.lookup(jndiName); cache.addService(service1); return service1; } }

Paso 6

UtilizarServiceLocatorpara demostrar el patrón de diseño de localizador de servicios.

ServiceLocatorPatternDemo.java

public class ServiceLocatorPatternDemo { public static void main(String[] args) { Service service = ServiceLocator.getService("Service1"); service.execute(); service = ServiceLocator.getService("Service2"); service.execute(); service = ServiceLocator.getService("Service1"); service.execute(); service = ServiceLocator.getService("Service2"); service.execute(); } }

Paso 7

Ejecutar el programa y mostrar el resultado:

Looking up and creating a new Service1 object
Executing Service1
Looking up and creating a new Service2 object
Executing Service2
Returning cached  Service1 object
Executing Service1
Returning cached  Service2 object
Executing Service2
Otras extensiones