2015-02-26 20 views
5

Kontekst:Fasada lub Dekorator

mam REST Usługi powiedzmy CustomerService który na razie ma jedną metodę getCustomer(id, country). Teraz wymaganie jest takie, że w zależności od kraju muszę wykonywać różne logiki biznesowe, takie jak dostęp do innej bazy danych lub niektórych reguł niestandardowych, a następnie zgłaszać, że otrzymałem takie żądanie.

Po pierwsze, aby rozwiązać różne implementacje zależnie od kraju użyłem wzoru fabryczne, jak pokazano poniżej:

wspólny interfejs dla wszystkich krajów implementacje oparte

public Interface CustomerServiceHandler{ 
    Cusomer getCustomer(String id, String country); 
} 

Następnie fabryka jako

public class CustomerServiceHandlerFactory{ 
    public CustomerServiceHandler getHandler(String country){...}; 
} 

Wdrażanie Szczegóły przy użyciu elewacji

Uwaga ta fasada jest wywoływana z klasy REST czyli CustomerService

public CustomerServiceFacade{ 
    public Customer getCustomer(String id, String country){ 
     //use factory to get handler and then handler.getCustomer 
     Customer customer = factory.getHandler(country).getCustomer(id,country); 
     //report the request 
     reportingService.report('fetch-customer',....); 
     return customer; 
    } 
} 

Przechodzenie przez SRP (Jednoosobowy odpowiedzialności co do zasady), to fasada nie jest osiągnięcie jednego celu. Ściąga klienta, a także informuje, że takie żądanie zostało otrzymane. Więc myślałem o wzorze dekoratora, jak następuje.

Realizacja użyciu Dekorator Wzorzec:

//this is called from Rest layer 
public ReportingCustomerHandler implements CustomerServiceHandler{ 
    //this delegate is basically the default implementation and has factory too      
    private CustomerServiceHandler delegate; 
    private ReportingService reporting; 
    public Customer getCustomer(String id, String country){ 
      Customer customer = delegate.getCustomer(id, country); 
      reporting.report(....); 
      return customer; 
    } 
} 


//this is called from ReportingCustomerHandler   
public DefaultCustomerServiceHandler implements CustomerServiceHandler{ 
    private CustomerServiceHandlerFactory factory;      

    public Customer getCustomer(String id, String country){ 
     //get factory object else use itself, even default implementation is provided by factory 
     CustomerServiceHandler handler = factory.getHandler(country); 
     return handler.getCustomer(id,country); 

    } 
} 

Uwaga W drugim podejściu jestem ponowne interfejs CustomerServiceHandler (pokazany w kodzie fabrycznym) dla Reporting and Default implementations również.

Więc jaki jest właściwy sposób, lub jaka jest alternatywa dla tego, jeśli jest coś bardziej odpowiedniego.

Druga część pytania

Co jeśli mam zachować dwa różne interfejsy to jeden CustomerServiceHandler realizacji wdrożenia różnych krajów i jeden służyć REST warstwy. Więc jaka może być konstrukcja lub alternatywa. W tym przypadku wydaje mi się, że fasada będzie pasować.

Odpowiedz

1

Więc co jest poprawny sposób, lub co jest alternatywą dla tego

masz solidną konstrukcję tutaj i świetny użytek z wzoru fabrycznego. To, co oferuję, to sugestie dotyczące tej dobrej pracy, ale myślę, że istnieje wiele sposobów na ulepszenie tego, co masz.

Widzę, gdzie CustomerServiceFacade metoda getCustomer łamie SRP. Łączy pobieranie klienta z aspektem raportowania. Zgadzam się, że czystsze byłoby przenoszenie sprawozdawczości z tej metody.

Następnie Twój obiekt będzie wyglądać następująco:

public CustomerServiceFacade{ 
    public Customer getCustomer(String id, String country){ 
     return factory.getHandler(country).getCustomer(id,country); 
    } 
} 

Więc gdzie stawiamy raportowanie?

Można przenosić raportowanie/zarządzać nim za pomocą osobnego interfejsu. Umożliwiłoby to elastyczność we wdrażaniu różnych metod raportowania i ułatwiłoby testowanie (np.

public interface ReportService { 
    void report(Customer c, String id, String country); 
} 

W jaki sposób raport dostępu do warstwy REST?

Wariant 1: REST dostęp do różnych funkcji klienta poprzez wielu obiektów

Realizacja ReportService można wstrzykiwać do kontrolera spoczywa na CustomerServiceFacade.

Nie wiesz, co ramy używasz na odpoczynek, ale tutaj jest, co to może wyglądać następująco:

@GET 
@Path("/customer/{Id}/{country}") 
public Response getCustomer(@PathParam("Id") String id, @PathParam("country") String country){ 

    Response r = null; 

    // injected implementation of CustomerServiceFacade 
    Customer c = customerServiceFacade.getCustomer(id, country); 
    if (c!=null){ 
     // injected implementation of ReportService 
     reportService.report(c, id, country); 
    } 
    else { 
     // handle errors ... 
    } 

    return r; 
} 

Opcja 2: REST dostęp do różnych funkcji klienta za pośrednictwem jednego elewacja/usługi

Mogłabyś pozwól, aby twoja warstwa elewacji usług pełniła funkcję udostępniania uproszczonego interfejsu większemu zestawowi obiektów, które zapewniają możliwości. Można to osiągnąć, stosując wiele metod obsługi klienta, które umożliwiają warstwy REST uzyskanie dostępu do różnych możliwości za pomocą jednego obiektu, ale nadal mają tę zaletę, że każda metoda jest ściślej powiązana z SRP.

Tutaj wstawiamy CustomerServiceFacade do kontrolera REST i wywołuje dwie metody 1), aby uzyskać klienta i 2) do obsługi raportowania. Fasada wykorzystuje implementację interfejsu ReportService od góry.

public CustomerServiceFacade{ 
    public Customer getCustomer(String id, String country){ 
     // call the correct CustomerServiceHandler (based on country) 
     return factory.getHandler(country).getCustomer(id,country); 
    } 

    public void report(Customer c, String id, String country){ 
     // call the reporting service 
     reportService.report(c, id, country); 
    } 
} 

Myślę, że jest to rozsądne wykorzystanie wzoru fasady, przy jednoczesnym zachowaniu SRP w ramach aktualnych metod.

Jeśli wdrażanie raportów różni się w zależności od kraju w taki sam sposób, w jaki działa Klient, można użyć innej fabryki.

public void report(Customer c, String id, String country){ 
     // call the correct reporting service (based on country) 
     rptFactory.getInstance(country).report(c,id,country); 
    } 
+0

dzięki za twoje dane wejściowe. Jeśli chodzi o raportowanie, nie chcę przenosić go do warstwy rest, ponieważ lubię utrzymywać warstwę Rest niezależną od dowolnej logiki, aby łatwo można było przełączać ten interfejs z dowolną implementacją. Co myślisz o wzorze dekoratora? – Sikorski

+0

dekorator może działać, ale twój 'ReportingCustomerHandler' ma wywołanie zarówno dla' getCustomer' i 'report', które naśladuje" problem ", który mieliśmy w' CustomerServiceFacade', więc starałem się zaprojektować od tego jak najwięcej. –