Service Locator-mønster og Java-implementering

1. Introduktion

I denne vejledning vil vi lære om Service Locator-designmønsteret i Java.

Vi beskriver konceptet, implementerer et eksempel og fremhæver fordele og ulemper ved dets anvendelse.

2. Forståelse af mønsteret

Formålet med Service Locator-mønsteret er at returnere serviceinstanserne efter behov. Dette er nyttigt til afkobling af serviceforbrugere fra betonklasser.

En implementering vil bestå af følgende komponenter:

  • Klient - klientobjektet er en serviceforbruger. Det er ansvarligt for at påkalde anmodningen fra servicelokatoren
  • Service Locator - er et kommunikationsindgangssted til returnering af tjenester fra cachen
  • Cache - et objekt til lagring af servicereferencer for at genbruge dem senere
  • Initializer - opretter og registrerer referencer til tjenester i cachen
  • Service - Servicekomponenten repræsenterer de oprindelige tjenester eller deres implementering

Det originale serviceobjekt er slået op af lokalisatoren og returneret efter behov.

3. Implementering

Lad os nu være praktiske og se på begreberne gennem et eksempel.

Først opretter vi en MessagingService interface til afsendelse af beskeder på forskellige måder:

offentlig grænseflade MessagingService {String getMessageBody (); String getServiceName (); }

Dernæst definerer vi to implementeringer af grænsefladen ovenfor, der sender beskeder via e-mail og SMS:

offentlig klasse EmailService implementerer MessagingService {public String getMessageBody () {returner "e-mail-besked"; } offentlig streng getServiceName () {returner "EmailService"; }}

Det SMSService klassedefinition svarer til EmailService klasse.

Efter at have defineret de to tjenester skal vi definere logikken for at initialisere dem:

public class InitialContext {public Object lookup (String serviceName) {if (serviceName.equalsIgnoreCase ("EmailService")) {returner ny EmailService (); } ellers hvis (serviceName.equalsIgnoreCase ("SMSService")) {returner ny SMSService (); } returnere null; }}

Den sidste komponent, vi har brug for, før vi sætter servicelokatorobjektet sammen, er cachen.

I vores eksempel er dette en simpel klasse med en Liste ejendom:

public class Cache {private List services = new ArrayList (); public MessagingService getService (String serviceName) {// hentes fra listen} public void addService (MessagingService newService) {// tilføj til listen}} 

Endelig kan vi implementere vores service locator klasse:

offentlig klasse ServiceLocator {privat statisk cache-cache = ny cache (); offentlig statisk MessagingService getService (String serviceName) {MessagingService service = cache.getService (serviceName); hvis (service! = null) {retur service; } InitialContext context = ny InitialContext (); MessagingService service1 = (MessagingService) kontekst. Lookup (serviceName); cache.addService (service1); retur service1; }}

Logikken her er ret enkel.

Klassen har en instans af Cache. Derefter i getService () metode, vil det først kontrollere cachen for en forekomst af tjenesten.

Så hvis det er nul, det kalder initialiseringslogikken og føjer det nye objekt til cachen.

4. Testning

Lad os se, hvordan vi kan få forekomster nu:

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

Første gang vi får EmailService fra ServiceLocator en ny forekomst oprettes og returneres. Derefter, efter at have kaldt det næste gang EmailService returneres fra cachen.

5. Service Locator vs Dependency Injection

Ved første øjekast kan Service Locator-mønster ligne et andet velkendt mønster - nemlig Dependency Injection.

For det første er det vigtigt at bemærke det både Dependency Injection og Service Locator-mønsteret er implementeringer af Inversion of Control-konceptet.

Inden du går videre, skal du lære mere om afhængighedsinjektion i denne opskrivning.

Hovedforskellen her er, at klientobjektet stadig opretter sine afhængigheder. Det bruger bare locatoren til det, hvilket betyder, at det har brug for en reference til locator-objektet.

Til sammenligning får klassen afhængigheder, når man bruger afhængighedsinjektionen. Injektoren kaldes kun én gang ved opstart for at injicere afhængigheder i klassen.

Lad os endelig overveje nogle få grunde til at undgå at bruge mønsteret Service Locator.

Et argument imod det er, at det vanskeliggør enhedstest. Med afhængighedsinjektion kan vi videregive objekter af den afhængige klasse til den testede instans. På den anden side er dette en flaskehals med Service Locator-mønsteret.

Et andet problem er, at det er vanskeligere at bruge API'er baseret på dette mønster. Årsagen til dette er, at afhængighederne er skjult inde i klassen, og de er kun verificeret ved kørsel.

På trods af alt dette er Service Locator-mønsteret let at kode og forstå og kan være et godt valg til små applikationer.

6. Konklusion

Denne vejledning viser, hvordan og hvorfor man bruger Design Locator-designmønsteret. Den diskuterer de vigtigste forskelle mellem Design Locator-designmønsteret og Dependency Injection-konceptet.

Generelt er det op til udvikleren at vælge, hvordan klasserne skal designes i applikationen.

Service Locator-mønster er et ligetil mønster til at afkoble koden. I tilfælde af brug af klasser i flere applikationer er afhængighedsindsprøjtning imidlertid et rigtigt valg.

Som sædvanlig er den komplette kode tilgængelig i Github-projektet.