Business Objects: contenitori o funzionali?

19

Questa è una domanda che ho chiesto un po 'su SO, ma potrebbe essere discusso meglio qui ...

Dove lavoro, siamo andati avanti e indietro su questo argomento un numero di volte e stiamo cercando un controllo di sanità mentale. Ecco la domanda: i Business Objects devono essere contenitori di dati (più come DTO ) o devono anche contenere la logica che può eseguire alcune funzionalità su quell'oggetto.

Esempio: prendi un oggetto cliente, probabilmente contiene alcune proprietà comuni (Nome, Id, ecc.), se quell'oggetto cliente include anche funzioni (Salva, Calc, ecc.)?

Una linea di ragionamento dice separare l'oggetto dalla funzionalità (principio di responsabilità singola) e inserire la funzionalità in un livello o oggetto di Business Logic.

L'altra linea di ragionamento dice, no, se ho un oggetto cliente voglio solo chiamare Customer.Save e averlo fatto. Perché devo sapere di un'altra classe per salvare un cliente se sto consumando l'oggetto?

I nostri ultimi due progetti hanno separato gli oggetti dalla funzionalità, ma il dibattito è stato sollevato di nuovo su un nuovo progetto.

Che ha più senso e perché ??

    
posta Walter 06.10.2010 - 11:39
fonte

7 risposte

5

Se si considera che un Cliente è una parte del modello di dominio, allora ha senso (specialmente nel contesto di DDD ma non limitato ad esso) avere entrambe le proprietà e le operazioni per quell'oggetto.

Detto questo, tuttavia, penso che l'esempio che hai usato sia scadente, ed è una causa dell'argomento. Se parli di persistenza, i clienti in genere non "salvano" se stessi; qualunque cosa tu stia usando per la persistenza. È logico che qualsiasi tipo di persistenza debba appartenere allo strato / partizione di persistenza. Questo è generalmente il pensiero dietro il modello di repository. ** Un metodo come Customer.UpgradeWarranty () o Customer.PromoteToPreferred () rende l'argomento più chiaro.

Questo non elimina la possibilità di avere DTO . Si consideri la situazione in cui si passeranno informazioni sui clienti a un servizio remoto, ad esempio. Potrebbe non avere senso che un cliente crei un DTO di per sé per il trasporto, è una questione architettonica, ma potrebbe esserci un caso nella persistenza o nel livello di rete / partizione / codice / what-have-you. In tal caso, tale oggetto potrebbe avere metodi che assomigliano a questo

public static CustomerDTO GetDTO(Customer c) { /* ... */ }

public static Customer GetCustomer(CustomerDTO cdto) { /* ... */ }

Quindi, in sintesi, ha perfettamente senso avere operazioni su un oggetto di dominio che sono congruenti con operazioni logiche nel dominio.

Google per "Persistence Ignorance" per una serie di buone discussioni sull'argomento ( questa domanda SO e la risposta accettata è un buon punto di partenza).

** Questo risulta un po 'confuso con alcuni software OR / M in cui sei costretto ad ereditare da una base persistente che ha un metodo' Salva '.

    
risposta data 06.10.2010 - 21:27
fonte
3

In realtà ho recentemente rielaborato del codice per separare gli oggetti dai dati. Il motivo è che i dati sono ottenuti attraverso un servizio separato, ed è molto più semplice passare semplicemente i dati grezzi al / dal server invece di passare l'intero oggetto avanti e indietro e dovendo gestire gli errori di convalida sul server. / p>

Per i piccoli progetti, avere oggetti contenenti la loro logica di business e dati probabilmente va bene, ma per progetti di grandi dimensioni, o progetti che potrebbero espandersi nel tempo, separerei sicuramente i livelli.

    
risposta data 06.10.2010 - 14:28
fonte
3

Penso che entrambi i modi per farlo possano avere i loro benefici, ma lo guarderei da una vista orientata agli oggetti o guidata da un dominio: quali sono le responsabilità delle diverse classi e oggetti.

Quindi, mi chiedo questo, nel tuo caso concreto: un cliente dovrebbe sapere come si salva?

Per me, la risposta sarebbe no: logicamente per me non ha senso, e un cliente non dovrebbe avere bisogno di sapere nulla di alcun quadro di persistenza (separazione delle responsabilità).

Come per gli esempi di SnOrfus con Customer.UpgradeWarranty () o Customer.PromoteToPreferred (), sono ovviamente più orientati alla logica di business di Customer.Save (). Ci sono diversi approcci a questo, ma ancora una volta se ti chiedi se un cliente dovrebbe essere in grado di aggiornare la sua garanzia, la risposta potrebbe essere sì o no, a seconda di come la si guarda:

  • sì: un cliente può ovviamente aggiornare la sua garanzia
  • no: un cliente potrebbe chiedere di essere aggiornato, ma l'aggiornamento è fatto da qualcun altro

Torna alla tua domanda originale; quale via abbia più senso dipenderà probabilmente da chi chiedi e dal loro metodo preferito, ma probabilmente la cosa più importante è attenersi a un solo modo per farlo.

Nella mia esperienza, però, separare i dati e la logica (aziendale) rende l'architettura più semplice, anche se non così eccitante.

    
risposta data 07.10.2010 - 10:05
fonte
2

Penso che tu stia specificamente parlando della differenza tra il modello ActiveRecord e il modello Repository . Nel primo caso, le entità sanno come persistere, e nel secondo il repository conosce la persistenza. Penso che quest'ultimo offra una migliore separazione delle preoccupazioni.

In senso più ampio, se le entità agiscono più come una struttura dati, allora non dovrebbero avere comportamenti, ma se hanno comportamenti, non dovrebbero essere usati come una struttura dati. Esempio:

Struttura dati:

class CustomerController
{
    public int MostRecentOrderLines(Customer customer)
    {
        var o = (from order in customer.Orders
                orderby order.OrderDate desc
                select order).First();
        return o.OrderLines.ToList().Count;
    }
}

Struttura non dati:

class Customer
{
    public int MostRecentOrderLines()
    {
        // ... same ...
    }
}

Nel primo caso, puoi navigare nella struttura della struttura dati del tuo modello senza problemi, da qualsiasi punto del tuo codice di lavoro, e va bene, perché lo stai trattando come una struttura di dati. In quest'ultimo caso, il Cliente è più simile a un servizio per un determinato cliente, quindi non è necessario chiamare metodi sul risultato. Tutte le cose che vuoi sapere sul Cliente dovrebbero essere disponibili chiamando un metodo sull'oggetto Cliente.

Quindi vuoi che le tue entità siano strutture dati o servizi? Per coerenza, sembra meglio attenersi a uno. Nel primo caso, inserisci la tua logica di tipo "servizio" da qualche altra parte, non nell'entità.

    
risposta data 14.11.2010 - 17:21
fonte
1

Non riesco davvero a rispondere alla tua domanda, ma trovo divertente anche la discussione in uno dei nostri progetti a scuola. Mi piacerebbe separare la logica dai dati. Ma molti dei miei compagni di classe dicono che l'oggetto deve contenere tutti i dati logici.

Cercherò di estetizzare i fatti che presentano:

  • Un oggetto business class rappresenta una cosa, quindi dovrebbe essere contenuta tutta la logica AND dei dati. (ad esempio se vuoi aprire una porta, lo fai da te, non chiedi a qualcun altro. cattivo esempio lo so)

  • Più facile capire il codice e la funzionalità di un oggetto bu.

  • Meno complessità nella progettazione

Sto dicendo loro che sono pigri e lo farei così:

  • Sì, le business class rappresentano le cose, quindi contengono dati. Ma sembra sbagliato salvare se stessi, o addirittura copiare. Non puoi farlo in rl.

  • Rendere l'oggetto responsabile di tutto ciò non fa bene alla durabilità e alla maneggevolezza in futuro. Se hai una classe separata che è responsabile del salvataggio, se aggiungi un nuovo oggetto alla progettazione, puoi facilmente implementare la sua funzione di salvataggio. invece di ricodificarlo di nuovo in quella classe.

  • Avendo un oggetto in grado di mantenere i dati, quell'oggetto può contenere una connessione al database e tutto il traffico del database viene guidato su quell'oggetto. (in modo basilare è il livello di accesso ai dati) altrimenti tutto l'oggetto Business dovrebbe mantenere una connessione. (che aggiunge complessità)

Beh, in un modo o nell'altro, ho intenzione di chiedere a un insegnante. Quando l'avrò fatto, invierò qui la sua risposta, se lo desideri. ;)

modifica

Ho dimenticato di menzionare che questo progetto riguardava un negozio di libri.

    
risposta data 06.10.2010 - 13:57
fonte
1

La risposta dipenderà davvero dalla tua architettura / design - un'architettura DDD con un modello di dominio sarà molto diversa da un modello CRUD centrato sui dati quando si tratta di design di oggetti.

In generale però, tenete presente che nella progettazione orientata agli oggetti si sta tentando di incapsulare lo stato ed esporre il comportamento. Ciò significa che di solito cercherai di ottenere lo stato associato a un comportamento il più vicino possibile a quel comportamento: quando non riesci a farlo, sei costretto a esporre lo stato in un modo o nell'altro.

In un modello di dominio si desidera separare il modello di business dai problemi di infrastruttura, quindi è assolutamente necessario evitare metodi come ".Save". Non ricordo l'ultima volta che ho "salvato" un cliente nella vita reale!

In un'applicazione CRUD, i dati sono cittadini di prima classe, quindi un ".Save" è del tutto appropriato.

La maggior parte delle applicazioni del mondo reale di grandi dimensioni avrà una miscela di questi paradigmi - modello di dominio dove ci sono regole aziendali in rapida evoluzione o complesse, DTO per il trasferimento dei dati oltre i confini, CRUD (o qualcosa tra CRUD e un modello di dominio, come activerecord ) altrove. Non esiste una regola adatta a tutte le dimensioni.

    
risposta data 14.11.2010 - 21:29
fonte
0

Sto rimuginando la stessa domanda per un po '- penso che il componente dati e il componente logico debbano essere separati. Ci credo perché ti porta nel giusto stato d'animo per quanto riguarda la logica di business come interfaccia per i dati che fornisce un significato.

Modificherei anche il punto di Scott Whitlock dall'alto (eccetto che non ho punti come nuovo membro), le classi di dati o di business logic non dovrebbero davvero preoccuparsi di come l'oggetto è memorizzato in modo persistente.

Detto questo, se si ha a che fare con un prodotto esistente, purché si disponga di interfacce contrattuali pulite - va bene anche se è mantenibile ...

    
risposta data 15.11.2010 - 09:16
fonte

Leggi altre domande sui tag