2016-11-09 6 views
0

Ich habe einen Basiscontroller (Spring MVC), der Benutzerdaten für meine Website erhält. Es hat verschiedene Endpunkte, die Daten in verschiedenen Umgebungsdatenquellen suchen/hinzufügen/aktualisieren können. Mein Problem ist, dass ich abhängig von Konfigurationswerten nur eine Liste von Benutzerdaten aus bestimmten Umgebungen lesen und zurückgeben muss (neben anderen Funktionen, die in diesem Beitrag weggelassen wurden).Delegierung der Serviceklasse

Ich habe eine Basisschnittstelle eingerichtet, um Benutzerdetails abzurufen, und Implementierungen für jede Datenquelle, die ich ausführen muss.

public interface BaseUserService { 
    //user service interface 
} 

@Service 
public class EnvironmentAService implements BaseUserService { 
    // do datasource specific dao stuff. 
} 

@Service 
public class EnvironmentBService implements BaseUserService { 
    // do datasource specific dao stuff. 
} 

@Service 
public class EnvironmentCService implements BaseUserService { 
    // do datasource specific dao stuff. 
} 

Zeit in meinem Controller ich so etwas wie dies tue:

@RestController 
@RequestMapping("api") 
public class UserController { 

    @Autowired 
    ConfigurationService configurationService 

    @Autowired 
    BaseUserService environmentAService; 

    @Autowired 
    BaseUserService environmentBService; 

    @Autowired 
    BaseUserService environmentCService; 

    @RequestMapping(value = "/users", method = RequestMethod.GET, headers={"Accept=application/json,application/xml"}) 
    public List<User> userList(
      @RequestParam(value="configValue") String configValue, 
      @RequestParam(value="username") String username, 
      @RequestParam(value="lastName") String configValue, 
      @RequestParam(value="dob") Date dateOfBirth 
      ){ 

     Configuration config = configurationService.getConfiguration(configValue); 

     if(config.value == null) 
      throw new ConfigurationNotFoundException("Please enter a valid configuration value"); 

     List<User> userList = new ArrayList<User> users; 

     if(config.environments.contains(Environment.A)) 
      userList.addAll(environmentAService.getUserList(username,configValue,dateOfBirth)); 
     if(config.environments.contains(Environment.B)) 
      userList.addAll(environmentBService.getUserList(username,configValue,dateOfBirth)); 
     if(config.environments.contains(Environment.C)) 
      userList.addAll(environmentCService.getUserList(username,configValue,dateOfBirth)); 

     return userList; 
    } 
} 

Dies funktioniert gut, aber ich bin für eine elegantere Lösung suchen, so dass die Steuerung nicht so in den Dienst gebunden ist Klassen. Ich untersuchte das Muster von Delegierten und Dekorateuren, um vielleicht die Bedingungen in einer Klasse unterzubringen, aber diese scheinen nicht zu funktionieren, oder ich weiß nicht genau, wie ich das in meinem Fall umsetzen soll.

+0

Fügen Sie eine Factory hinzu, die den angeforderten Typ von Dienstinstanzen basierend auf den konfigurierten Umgebungen zurückgibt. Durchlaufen Sie die zurückgegebenen Instanzen, um die Benutzerliste zu erstellen. – dbugger

Antwort

1

Wie wäre es mit einer Karte von BaseUserService statt einzelner Felder?

@Autowired 
Map<Environment, BaseUserService> serviceMap; 

... 

for (Entry<Environment, BaseUserService> e : serviceMap.entrySet()) { 
    if (config.environments.contains(e.getKey())) { 
     userList.addAll(e.getValue().getUserList(username,configValue,dateOfBirth)); 
    } 
} 

Auf diese Weise können Sie neue Dienste injizieren, ohne Ihren Controller ändern zu müssen.

+0

Es hat funktioniert! sehr schöne Lösung. Es macht das Hinzufügen von Diensten für andere Umgebungen kinderleicht! – ephemeralCoder

0

Sie können sich vorstellen, dafür Visitor Pattern zu verwenden.

Einige Ideen:

  • Jeder environment in config.environments eine Besuchbar wird.
  • Erstellen Sie einen Besucher, sagen Sie UpdateUserListFromServiceVisitor. Die visit(Environment.A)-Methode verwendet eine Instanz von EnvironmentAService zum Abrufen der Benutzerliste. In ähnlicher Weise verwendet visit(Environment.B)EnvironmentBService und visit(Environment.C) verwendet EnvironmentCService.

Vorteile dieses Ansatzes:

  • Sie, dass hässliche in der Steuerung if-else-Block loszuwerden.
  • Das Hinzufügen eines neuen BaseUserService würde keine Änderung Ihrer Controller erfordern. Ändern Sie einfach die Besucherklasse.
  • Derzeit benötigen Sie die Benutzerliste von BaseUserService s. Wenn Sie in Zukunft weitere Vorgänge hinzufügen, müssen Sie nur einen neuen Besucher hinzufügen.

Caveats: - Wenn config.environments doppelte Einträge enthalten kann, das Besuchermuster oben beschrieben machen doppelte Anrufe BaseUserService entspricht. Sie können es in eine Set konvertieren.

Verwandte Themen