2012-02-21 18 views
10

Stiamo cercando nella creazione di un nuovo progetto e sono desiderosi di esplorare utilizzando i modelli di repository e livello di servizio, al fine di creare è senza bloccare il codice abbinato che è completamente verificabile tramite repository finte.C# Servizi Strato Design Pattern

prega di vedere sotto l'idea di architettura di base. Utilizzeremo le interfacce per descrivere i repository e inserirli nei livelli di servizio per rimuovere eventuali dipendenze. Quindi utilizzando autofac, i servizi verranno cablati in fase di runtime.

public interface IOrderRepository 
{ 
    IQueryable<Order> GetAll(); 
} 

public class OrderRepository : IOrderRepository 
{ 
    public IQueryable<Order> GetAll() 
    { 
     return new List<Order>().AsQueryable(); 
    } 
} 

public class OrderService 
{ 
    private readonly IOrderRepository _orderRepository; 

    public OrderService(IOrderRepository orderRepository) 
    { 
     _orderRepository = orderRepository; 
    } 

    public IQueryable<Order> GetAll() 
    { 
     return _orderRepository.GetAll(); 
    } 
} 

public class EmailService 
{ 
    public void SendEmails() 
    { 
     // How do I call the GetAll method from the order serivce 
     // I need to inject into the orderService the repository to use 
    } 
} 

Ci sono alcune domande che stiamo avendo problemi a trovare il modo migliore di procedere.

1) Qualora il servizio sia riproducendo i metodi CRUD, così come appare possiamo essere riproducendo codice con alcun beneficio reale. O l'interfaccia utente dovrebbe chiamare direttamente i repository?

2) Cosa succede quando un servizio ha bisogno di chiamare un altro servizio. Nel nostro esempio precedente, se il servizio di posta elettronica ha bisogno di ricevere tutti gli ordini, inseriamo il servizio di ordine nel servizio di posta elettronica?

Spero che questo ha un senso

+0

servizio e-mail non deve essere a conoscenza di servizi come OrderService, è necessario mediatore di lavorare con entrambi i servizi e-mail && ordine in modo sarebbero stati disaccoppiati – sll

+0

cosa fa il tuo servizio di ordine fare? Basta incapsulare il OrderRepository? O fa di più, dall'aspetto del tuo codice sembra solo un livello ridondante. – gideon

+0

Vorrei fare un'altra domanda. È opportuno esporre IQueryable al di fuori del limite del repository? Per me no. È un'astrazione che perde. –

risposta

2

servizio e-mail non deve essere a conoscenza di servizi come OrderService, è necessario Mediator di lavorare sia con e-mail & & servizi d'ordine in modo che sarebbero stati disaccoppiati, o Adapter di adattarsi IOrder-IEmail:

IEnumerable<IOrder> orders = orderService.GetAll(); 

// TODO: Create emails from orders by using OrderToEmailAdaptor 
IEnumerable<IEmail> emails = ... 
emailService.SendEmails(emails); 

public sealed class EmailService 
{ 
    public void SendEmails(IEnumerable<IEmail> emails) 
    { 
    } 
} 

Mediatore:

Definire un oggetto che incapsula il modo in cui un insieme di oggetti interagisce. mediatore promuove accoppiamento lasco mantenendo oggetti dal menzionare reciprocamente esplicitamente, e permette di variare la loro interazione indipendentemente

adattatore:

Il pattern adattatore (spesso indicato come il modello involucro o semplicemente un wrapper) è un modello di progettazione che si traduce un'interfaccia per una classe in un'interfaccia compatibile

+1

+1 Per mediatore ho pensato che ti stavi riferendo al modello di mediatore per un secondo, ma questo è corretto e semplice! :) Non penso che sia richiesto un servizio di ordini, ma il repository si occupa già del disaccoppiamento ** in che modo ** gli ordini vengono recuperati? – gideon

+0

Ciao, grazie per il tuo feedback. Nell'esempio sopra chi chiamerebbe il metodo SendEmails? Non avresti ancora bisogno del codice da qualche parte per ricevere gli ordini e poi chiamare il servizio di posta elettronica? – user1223218

+0

@ user1223218: questo potrebbe essere un mediatore. Considerando i requisiti, chi sta determinando quando è il momento di chiamare 'SendEmails()', è qualche gestore di eventi? – sll

0

Cosa avrei fatto io è

  1. non chiama repository direttamente dall'interfaccia utente, ma chiamare il servizio al posto e il servizio dovrebbe utilizzare il repository,

  2. vorrei la chiamata al metodo dell'ordine repository dal servizio di posta elettronica, in questo modo avrei solo iniettare OrderRepository al servizio di posta elettronica (non ordinare il servizio)

+0

Grazie per la tua risposta, se il servizio di posta elettronica utilizza direttamente il repository non corriamo il rischio di azioni diverse che accadono poiché GetAll() può essere cambiato nel servizio in modo diverso da GetAll() dal repository. Grazie – user1223218

2

Dai un'occhiata a Domain Driven Design. DDD trasferisce la maggior parte della logica nelle entità (Order, Email) e consente loro di utilizzare i repository.

1) Qualora il servizio sia riproducendo i metodi CRUD, così come appare possiamo essere riproducendo codice con alcun beneficio reale. O l'interfaccia utente dovrebbe chiamare direttamente i repository?

Un servizio in DDD viene utilizzato quando ci si trova a scrivere business logic al di fuori delle entità.

2) Cosa succede quando un servizio deve chiamare un altro servizio. Nel nostro esempio precedente, se il servizio di posta elettronica ha bisogno di ricevere tutti gli ordini, inseriamo il servizio di ordine nel servizio di posta elettronica?

Iniettarlo nel costruttore. Tuttavia, il servizio ordini dovrebbe inviare una e-mail, non il contrario.

L'approccio DDD sarebbe quello di creare un OrderNotificationService che prende l'evento dominio OrderCreated e compone una e-mail che invia tramite l'Aggiornamento EmailService

Mi missunderstood. La logica duplicata non è mai buona. Non metterei un metodo nel mio servizio chiamato GetAll quando il mio repository ne ha uno. Nemmeno metterei quel metodo nella mia entità.

codice Esempio:

var order = repository.Create(userId); 
order.Add(articleId, 2); 
order.Save(); // uses the repository 

Order.Send() dovrebbe creare un evento dominio che il OrderNotificationService può prendere.

Update2

Repository.Create è solo un metodo factory (google factory method pattern) per ottenere tutte le creazioni del modello di dominio in un unico luogo. Non fa nulla nel db (anche se potrebbe nelle versioni future).

Per quanto riguarda order.Save utilizza il repository per salvare tutte le righe dell'ordine, l'ordine stesso o qualsiasi altra cosa necessaria.

+0

Ciao, grazie per la tua risposta. Se l'ordine dovesse avere metodi come Order.GetAll() non accoppiato, come ordinarebbe quale repository usare? Grazie – user1223218

+0

+1 - OrderNotificationService suona sicuramente più come il modo corretto per me. –

+0

@ user1223218: leggi il mio aggiornamento. – jgauffin

0

è possibile utilizzare modello adattatore o utilizzando strumenti DI

public class EmailService 
{ 
    private IOrderRepository _orderservice = null; 

    public EmailService(IOrderService orderservice) 
    { 
     _orderservice = orderservice; 
    } 

    public void SendEmails() 
    { 
     _orderService.GetAll(); 
    } 
}