Pattern di localizzazione del servizio e implementazione di Java

1. Introduzione

In questo tutorial, impareremo a conoscere il modello di progettazione del localizzatore di servizi in Java .

Descriveremo il concetto, implementeremo un esempio ed evidenzieremo i pro ei contro del suo utilizzo.

2. Capire il modello

Lo scopo del pattern Service Locator è restituire le istanze del servizio su richiesta. Ciò è utile per separare i consumatori di servizi dalle classi concrete.

Un'implementazione consisterà dei seguenti componenti:

  • Client: l'oggetto client è un consumatore di servizi. È responsabile del richiamo della richiesta dal localizzatore di servizi
  • Service Locator: è un punto di ingresso della comunicazione per la restituzione dei servizi dalla cache
  • Cache: un oggetto per la memorizzazione dei riferimenti al servizio per riutilizzarli in seguito
  • Inizializzatore: crea e registra i riferimenti ai servizi nella cache
  • Servizio: il componente Servizio rappresenta i servizi originali o la loro implementazione

L'oggetto del servizio originale viene cercato dal localizzatore e restituito su richiesta.

3. Implementazione

Ora, mettiamoci in pratica e diamo uno sguardo ai concetti attraverso un esempio.

Innanzitutto, creeremo un'interfaccia MessagingService per inviare messaggi in diversi modi:

public interface MessagingService { String getMessageBody(); String getServiceName(); }

Successivamente, definiremo due implementazioni dell'interfaccia sopra, che inviano messaggi tramite e-mail e SMS:

public class EmailService implements MessagingService { public String getMessageBody() { return "email message"; } public String getServiceName() { return "EmailService"; } }

La definizione della classe SMSService è simile alla classe EmailService .

Dopo aver definito i due servizi, dobbiamo definire la logica per inizializzarli:

public class InitialContext { public Object lookup(String serviceName) { if (serviceName.equalsIgnoreCase("EmailService")) { return new EmailService(); } else if (serviceName.equalsIgnoreCase("SMSService")) { return new SMSService(); } return null; } }

L'ultimo componente di cui abbiamo bisogno prima di mettere insieme l'oggetto localizzatore di servizi è la cache.

Nel nostro esempio, questa è una classe semplice con una proprietà List :

public class Cache { private List services = new ArrayList(); public MessagingService getService(String serviceName) { // retrieve from the list } public void addService(MessagingService newService) { // add to the list } } 

Infine, possiamo implementare la nostra classe di localizzazione dei servizi:

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

La logica qui è abbastanza semplice.

La classe contiene un'istanza di Cache. Quindi, nel metodo getService () , controllerà prima la cache per un'istanza del servizio.

Quindi, se è nullo, chiamerà la logica di inizializzazione e aggiungerà il nuovo oggetto alla cache.

4. Test

Vediamo ora come possiamo ottenere istanze:

MessagingService service = ServiceLocator.getService("EmailService"); String email = service.getMessageBody(); MessagingService smsService = ServiceLocator.getService("SMSService"); String sms = smsService.getMessageBody(); MessagingService emailService = ServiceLocator.getService("EmailService"); String newEmail = emailService.getMessageBody();

La prima volta che otteniamo l'EmailService dal ServiceLocator viene creata una nuova istanza e restituito . Quindi, dopo averlo chiamato la prossima volta, EmailService verrà restituito dalla cache.

5. Service Locator vs Dependency Injection

A prima vista, il pattern Service Locator può sembrare simile a un altro pattern ben noto, vale a dire, Dependency Injection.

Innanzitutto, è importante notare che sia l'inserimento delle dipendenze che il pattern Service Locator sono implementazioni del concetto di inversione del controllo .

Prima di andare oltre, scopri di più su Dependency Injection in questo articolo.

La differenza fondamentale qui è che l'oggetto client crea ancora le sue dipendenze . Usa solo il localizzatore per questo, il che significa che ha bisogno di un riferimento all'oggetto localizzatore.

In confronto, quando si utilizza l'inserimento delle dipendenze, alla classe vengono assegnate le dipendenze. L'iniettore viene chiamato solo una volta all'avvio per iniettare le dipendenze nella classe.

Infine, consideriamo alcuni motivi per evitare di utilizzare il pattern Service Locator.

Un argomento contro è che rende difficili i test unitari. Con l'inserimento delle dipendenze, possiamo passare oggetti fittizi della classe dipendente all'istanza testata. D'altra parte, questo è un collo di bottiglia con il pattern Service Locator.

Un altro problema è che è più complicato utilizzare le API basate su questo modello. Il motivo è che le dipendenze sono nascoste all'interno della classe e vengono verificate solo in fase di esecuzione.

Nonostante tutto ciò, il pattern Service Locator è facile da codificare e comprendere e può essere un'ottima scelta per piccole applicazioni.

6. Conclusione

Questa guida mostra come e perché utilizzare il modello di progettazione del localizzatore di servizi. Discute le differenze chiave tra il modello di progettazione del localizzatore di servizi e il concetto di inserimento delle dipendenze.

In generale, spetta allo sviluppatore scegliere come progettare le classi nell'applicazione.

Il pattern Service Locator è un pattern semplice per disaccoppiare il codice. Tuttavia, in caso di utilizzo delle classi in più applicazioni, l'inserimento delle dipendenze è una scelta giusta.

Come al solito, il codice completo è disponibile nel progetto Github.