Spargimento di informazioni attraverso i confini degli oggetti


10

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

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

Ma poi scopriamo che alcuni articoli sono venduti con un affare due per uno. Possiamo gestirlo facendo OrderItem.GetPrice () fare qualcosa come InventoryItem.GetPrice (quantità) e lasciando che InventoryItem gestisca questo.

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

Ma allora abbiamo bisogno di supportare prezzi diversi a seconda di quanto tempo il cliente è rimasto nel sistema: InventoryItem.GetPrice (quantità, order.GetDate (), order.GetCustomer ())

Ma poi si scopre che le offerte due-a-uno si applicano non solo all'acquisto di più articoli dello stesso inventario, ma anche a multipli per qualsiasi articolo in una InventoryCategory. A questo punto alziamo le mani e diamo semplicemente all'InventoryItem l'articolo dell'ordine e gli consentiamo di spostarsi sul grafico di riferimento dell'oggetto tramite gli accessori per ottenere le informazioni di cui ha bisogno: InventoryItem.GetPrice (questo)

TL; DR Voglio avere un basso accoppiamento negli oggetti, ma le regole aziendali spesso mi costringono ad accedere alle informazioni da tutto il luogo per prendere decisioni particolari.

Ci sono buone tecniche per affrontarlo? Altri trovano lo stesso problema?


4
A prima vista sembra che la classe InventoryItem stia tentando di fare troppo calcolando il prezzo, restituire un determinato prezzo è una cosa, ma i prezzi di vendita e le regole commerciali speciali non dovrebbero essere indirizzi in InventoryItem. Distribuire una classe per il calcolo dei prezzi e lasciare che gestisca la necessità di dati provenienti da ordine, inventario e cliente e così via.
Chris

@ Chris, sì, dividere la logica dei prezzi è probabilmente una buona idea. Il mio problema è che un tale oggetto sarà strettamente accoppiato a tutti gli oggetti relativi all'ordine. Questa è la parte che mi dà fastidio e la parte che mi chiedo se posso evitare.
Winston Ewert,

1
Se qualcosa, non voglio chiamarlo in alcun modo, ho bisogno di tutte quelle informazioni, quindi in qualche modo deve consumare queste informazioni per produrre il risultato desiderato. Se si dispone già di inventario, articolo, cliente e così via, l'implementazione della logica aziendale nella propria area ha più senso. Non ho davvero una soluzione migliore.
Chris,

Risposte:


6

Abbiamo praticamente avuto la stessa esperienza in cui lavoro e l'abbiamo affrontata con 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 consideriamo come una "esecuzione commerciale" e la classe OrderBL ricalcola i totali attraversando gli oggetti necessari.

È una soluzione perfetta, no. Abbiamo ancora una classe che conosce troppo le altre classi, ma almeno abbiamo spostato quel bisogno fuori dagli oggetti di business e in una classe di logica di business.


2
In caso di dubbio aggiungere un'altra classe.
Chris

1

Sembra che avete bisogno di un oggetto separato sconto (o un elenco di loro) che tiene traccia di tutta quella roba, e poi applicare lo sconto (s) per l'Ordine, qualcosa di simile Order.getTotal(Discount)o di Discount.applyTo(Order)o simili.


Posso vedere dove sarebbe meglio inserire il codice in uno sconto piuttosto che nell'oggetto Inventario. Sembra che l'oggetto sconto debba comunque accedere alle informazioni di tutti i diversi oggetti per fare il proprio lavoro. Quindi questo, almeno per quanto posso vedere, non risolve il problema.
Winston Ewert,

2
Penso che l'oggetto Discount sia una buona idea, ma lo farei implementare un modello di osservatore ( en.wikipedia.org/wiki/Observer_pattern ), con gli Sconti come soggetto (i) del modello
BlackICE

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. Ciò che penso manchi nella tua Classe d'ordine è una sorta di logica aziendale che può o meno giustificare una classe come quella suggerita da Walter.

Modifica: risposta al commento di Winston

Non penso che tu abbia bisogno di un oggetto 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 di inventario con un ID. Ogni ordine conterrebbe un elenco di ID inventario e una quantità corrispondente.

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

Quindi potresti avere altre funzioni di supporto come:

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


Va benissimo chiedere dati a classi strettamente correlate. Il problema sorge quando accedo ai dati da classi indirettamente correlate. L'implementazione di tale logica nella classe Order richiederebbe che la classe Order sia gestita direttamente con l'oggetto Inventory (che contiene i dati di prezzo necessari). Questa è la parte che mi dà fastidio perché sta accoppiando l'Ordine a classi di cui (idealmente) non ne saprebbe nulla.
Winston Ewert,

In sostanza, la tua idea sarebbe quella di eliminare OrderItem, invece Order tiene traccia di tutte quelle informazioni stesse. È quindi facile trasferire tali informazioni a un altro oggetto per informazioni sui prezzi. Potrebbe funzionare. (Nel particolare scenario questo esempio è vagamente basato sull'Ordine Ordine era troppo complicato e doveva davvero essere il suo oggetto)
Winston Ewert,

Ciò che non ha senso per me è il motivo per cui si desidera che l'inventario venga referenziato utilizzando i numeri ID anziché i riferimenti agli oggetti. Mi sembra molto meglio tenere traccia dei riferimenti e delle quantità degli oggetti, quindi degli ID e dei riferimenti degli articoli.
Winston Ewert,

Non lo sto proprio suggerendo affatto. Penso che dovresti avere ancora una classe o una struttura per gli articoli dell'ordine. Semplicemente non penso che i singoli oggetti di inventario debbano avere il prezzo al loro interno principalmente perché non sono sicuro di come lo otterresti senza chiedere una sorta di database. L'ordine o l'articolo di inventario sarebbe rigorosamente una classe di dati contenente un identificatore di articolo e una quantità. L'ordine stesso avrebbe un elenco di questi oggetti.
Pemdas,

Non sono proprio sicuro di ciò che stai chiedendo nel secondo commento. Non tutto deve essere un oggetto. Non sono davvero sicuro di come individuare un articolo specifico senza una sorta di ID.
Pemdas,

0

Dopo averci pensato di più, ho escogitato una mia strategia alternativa.

Definire 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 di prezzo (e forse alcune classi correlate) incapsulano la logica dei prezzi e l'ordine non deve preoccuparsene. Il prezzo non sa nulla di Order / OrderItem invece di avere semplicemente le informazioni in esso contenute.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.