Spargimento di informazioni tra i confini degli oggetti

10

Molte volte i miei oggetti business tendono ad avere situazioni in cui le informazioni devono attraversare i confini degli oggetti troppo spesso. Quando facciamo OO, vogliamo che le informazioni siano in un oggetto e quanto più possibile tutto il codice che si occupa di quell'informazione dovrebbe essere in quell'oggetto. Tuttavia, le regole aziendali non seguono questo principio mi dà problemi.

Come esempio supponiamo di avere un Ordine che ha un numero di OrderItem che si riferisce a un InventoryItem che ha un prezzo. Invoco Order.GetTotal () che somma il risultato di OrderItem.GetPrice () che moltiplica una quantità di InventoryItem.GetPrice (). Fin qui tutto bene.

Ma poi scopriamo che alcuni articoli sono venduti con un affare due per uno. Possiamo gestirlo avendo OrderItem.GetPrice () fare qualcosa come InventoryItem.GetPrice (quantità) e lasciare che InventoryItem si occupi di questo.

Tuttavia, scopriamo che l'accordo due per uno dura solo un determinato periodo di tempo. Questo periodo di tempo deve essere basato sulla data dell'ordine. Ora cambiamo OrderItem.GetPrice () per essere InventoryItem.GetPrice (quatity, order.GetDate ())

Ma poi dobbiamo sostenere prezzi diversi a seconda di quanto tempo il cliente è stato nel sistema: InventoryItem.GetPrice (quantità, order.GetDate (), order.GetCustomer ())

Ma poi si scopre che le offerte "due per uno" non si applicano solo all'acquisto di più articoli dello stesso inventario ma più di un articolo in un InventoryCategory. A questo punto ci alziamo le mani e basta dare l'oggetto Inventory all'oggetto dell'ordine e permettergli di viaggiare sul grafico di riferimento dell'oggetto tramite gli accessor per ottenere le informazioni necessarie: InventoryItem.GetPrice (this)

TL; DR Voglio avere un basso accoppiamento negli oggetti, ma le regole aziendali spesso mi costringono ad accedere a informazioni da ogni parte per prendere decisioni particolari.

Ci sono buone tecniche per affrontare questo? Gli altri trovano lo stesso problema?

    
posta Winston Ewert 03.01.2011 - 18:10
fonte

4 risposte

6

Abbiamo praticamente avuto la stessa esperienza in cui lavoro e ci siamo occupati di avere una classe OrderBusinessLogic. Per la maggior parte il layout che hai descritto funziona per la maggior parte della nostra attività. È bello, pulito e semplice. Ma in quelle occasioni in cui hai acquistato 2 da questa categoria, la trattiamo come un "business execption" e la classe OrderBL ricalcola i totali attraversando gli oggetti necessari.

È una soluzione perfetta, no. Abbiamo ancora una classe che sa troppo delle altre classi, ma almeno abbiamo spostato quella necessità dagli oggetti di business e in una classe di business logic.

    
risposta data 03.01.2011 - 18:22
fonte
1

Sembra che tu abbia bisogno di un oggetto Discount separato (o un elenco di essi) che tenga traccia di tutte quelle cose, e poi applichi gli sconti sull'ordine, qualcosa come Order.getTotal(Discount) o Discount.applyTo(Order) o simile.

    
risposta data 03.01.2011 - 19:53
fonte
1

È perfettamente accettabile accedere ai dati di altre classi. Tuttavia, vuoi che questa sia una relazione unidirezionale. Ad esempio, supponiamo che ClassOrder acceda a CallItem. Idealmente, ClassItem non dovrebbe accedere a ClassOrder. Quello che penso che manchi nella tua classe di ordine è una sorta di logica aziendale che può o non può garantire una classe come suggerito da Walter.

Modifica: risposta al commento di Winston

Non penso che tu abbia bisogno di un oggetto item di inventario ... almeno nel modo in cui lo stai usando. Avrei invece una classe di inventario che gestiva un database di inventario.

Vorrei fare riferimento agli articoli dell'inventario con un ID. Ogni ordine conterrebbe un elenco di ID di inventario e una quantità corrispondente.

Quindi calcolerei il totale dell'ordine con qualcosa di simile.
Inventory.GetCost (Articoli, customerName, data)

Quindi potresti avere altre funzioni di aiuto come:

Inventory.ItemsLefts (int itemID)
Inventory.AddItem (int itemID, int quantity)
Inventory.RemoveItem (int itemID, int quantity)
Inventory.AddBusinessRule (...)
Inventory.DeleteBusinessRule (...)

    
risposta data 03.01.2011 - 18:44
fonte
0

Dopo averci pensato di più, ho trovato la mia strategia alternativa.

Definisci una classe di prezzo. Inventory.GetPrice() restituisce un oggetto prezzo

Price OrderItem::GetPrice()
{
    return inventory.GetPrice().quantity(quantity);
}

Currency OrderItem::GetTotal()
{
    Price price = empty_price();
    for(item in order_items)
    {
         price = price.combine( item.GetPrice() )
    }
    price = price.date(date).customer(customer);
    return price.GetActualPrice();
}

Ora la classe Price (e possibilmente alcune classi correlate) incapsulano la logica del prezzo e l'ordine non deve preoccuparsi di ciò. Il prezzo non sa nulla di Order / OrderItem, invece di avere semplicemente delle informazioni alimentate in esso.

    
risposta data 03.01.2011 - 20:54
fonte

Leggi altre domande sui tag