Business Layer Procedural?

4

Il modo più comune che ho visto di salvare un'entità in un database è attraverso una classe in un livello di business / servizio. Ad esempio, quando aggiungi una nuova entità chiamata User :

User user = new User();
user.Name = "Foo";

UserService userService = new UserService();
userService.Add(user);

Funziona e gli oggetti vengono utilizzati, ma ritengo che lo stile sia inclinato verso il lato procedurale. Di solito, la classe UserService contiene principalmente metodi per interagire con il database. Potresti quasi rendere statica la UserService class e quindi non sarà più considerata come un oggetto.

In un modo puramente orientato agli oggetti, sento che il codice sarebbe simile a questo:

User user = new User();
user.Name = "Foo";
user.Add();

La mia domanda non riguarda dettagli specifici dell'implementazione, ma la progettazione orientata agli oggetti in generale. Usare classi come nell'esempio UserService indica un modo procedurale di codifica? Se sì, quale potrebbe essere un approccio migliore orientato agli oggetti?

Un esempio del framework .NET che ritengo sia più orientato agli oggetti è SqlConnection . Come apriamo una connessione? Esiste una classe SqlService da cui è possibile chiamare sqlService.Open(sqlConnection) ? No, ma viene eseguito dall'oggetto SqlConnection stesso: sqlConnection.Open() .

Ora il metodo Open può utilizzare altre classi a sua volta, ma ciò che è interessante per me è che è esposto sulla classe SqlConnection stessa, proprio come il metodo Add è esposto nella classe User nel secondo frammento sopra.

    
posta OJ Raqueño 14.05.2015 - 04:40
fonte

4 risposte

5

Uno dei principi del design orientato agli oggetti è che ogni oggetto (classe) dovrebbe fare solo una cosa. La classe User dovrebbe sapere tutto sull'essere un utente, ma questo non include sapere dove sono archiviati gli utenti - tale responsabilità è per un'altra classe (la tua classe UserService ).

La classe UserService dovrebbe sapere tutto sull'archiviazione degli utenti, ma non ha bisogno di sapere nulla sull'interno di ciò che è User - solo che ha bisogno di memorizzarlo. Quando lo guardi da questa prospettiva, ha senso passare l'oggetto user a userService , perché nell'altro scenario un User dovrebbe sapere come memorizzare se stesso.

    
risposta data 14.05.2015 - 06:21
fonte
2

Quello che stai descrivendo è chiamato Pattern di registrazione attiva .

Come sottolinea Jack, ci sono molti problemi con questo modello, specialmente in relazione alla separazione di preoccupazioni, modellazione di dominio e test. Se si utilizza il record attivo, si assume che le classi siano esattamente uguali alle tabelle e alle righe nel database relazionale. Questo limita le opzioni di modellazione. L'oggetto diventa anche strettamente associato alla libreria di persistenza, rendendo difficile testarlo separatamente.

Tuttavia il schema del repository ha i suoi problemi. Richiede che il repository sia in grado di leggere e scrivere lo stato interno dell'entità di cui è responsabile, interrompendo l'incapsulamento. Inoltre, non si adatta perfettamente quando si utilizza ORM, in cui le modifiche apportate all'oggetto devono essere mantenute in modo trasparente, eliminando la necessità di qualsiasi metodo di salvataggio / aggiornamento.

    
risposta data 14.05.2015 - 10:15
fonte
1

Non vedo alcun problema.

Hai due oggetti distinti: User e UserService . Entrambi hanno due distinti ruoli / responsabilità.

1) L'oggetto User rappresenta l' utente nel tuo dominio. Risponde a domande / messaggi come età? o firstname? . È suo dovere rispondere a questi tipi di domande.

2) UserService è diverso da User . Risponde non alle domande precedenti, ma a un diverso impostato come: userCount? , countOfUKUsers? . La responsabilità è molto diversa. Il User non si cura di nessun numero, né deve sapere nulla di persistente. UserService consuma quindi dire un User o produce nuove istanze, quando si restituiscono dati dal database.

UserService userService = new UserService();
userService.Add(user);

Questo è perfettamente orientato agli oggetti - anche se di solito dovresti inject del servizio (che ti fa sembrare procedurale ): Alla UserService viene inviato un messaggio Add e il messaggio ha un payload , che è un User .

Ma il tuo secondo codice di esempio sopra non ha una chiara semantica

user.Add();

Stai inviando il messaggio Add() a User . Ma cosa significa? È come chiedersi per ascoltare . È grammaticalmente corretto, ma non ha alcun senso. Inoltre: mescolerai le tue conoscenze sulla persistenza con la conoscenza effettiva di User stessa, che viola il modello di responsabilità singola.

Does using classes like the example UserService indicate a procedural way of coding?

NO. È perfettamente OOP: passare messaggi a oggetti indipendenti.

    
risposta data 14.05.2015 - 12:52
fonte
0

Una domanda molto vicina al mio cuore! (vedi la mia domanda OOP vs ADM)

Sì, credo che sia IS procedurale, ma solo se il tuo UserService modifica l'utente.

per esempio, considera un Ordine che ha molti Articoli

Order.AddItem (Item Item)

sarebbe OOP sicuramente?

ma

Order.SetItemPrice (Elemento articolo, prezzo decimale)

dove Item ha Item.Price, rompe il principio di incapsulamento. ti aspetteresti

Item.SetPrice (prezzo decimale)

Ora, c'è potenzialmente un ulteriore fattore che, poiché stai scrivendo su un database, avrai bisogno di vedere tutti i campi dati privati sull'utente. ma, davvero in questi giorni di ORM e serializzatori che usano comunque la riflessione sugli oggetti. A meno che il tuo schema non ti costringa a rendere pubblici tutti i campi altrimenti privati, non penso che tu possa considerare "non OOP"

Inoltre potresti avere

User.SerialiseToXML () o qualcosa che non interromperebbe l'incapsulamento

Ora la tua seconda domanda "Quale sarebbe un modo migliore OOP" pone la domanda. Un modo OOP è sempre migliore?

    
risposta data 14.05.2015 - 13:09
fonte

Leggi altre domande sui tag