In questo caso è possibile utilizzare Visitor design pattern. Nella classe Product
implementare il metodo addToBill
e passare come argomento un'istanza che implementa l'interfaccia di fatturazione, IBill
. IBill
supporta un metodo addToTotal
che accetta tutte le informazioni necessarie disponibili nell'elemento; nel tuo caso, questo è un prezzo Ad esempio:
interface IBill {
/* needs to be public because PHP doesn't understand the concept of
friendship
*/
function addToTotal($price);
}
class Bill implements IBill {
private $total = 0;
function addToTotal($price) {
$this->total += $price;
}
...
}
class ShoppingCart {
private $items = array();
function addItem($id, $product, $quantity) {
if (isset($this->items[$id])) {
$this->items[$id]->addQuantity($quantity);
} else {
$this->items[$id] = new LineItem($product, $quantity);
}
}
private createBill() {
$bill = new Bill;
foreach ($this->items AS $lineItem) {
$lineItem->addToBill($bill);
}
return ...;
}
}
class LineItem {
private $product, $quantity;
function __constructor($product, $quantity) {...}
function addToBill(IBill $bill) {
$this->product->addToBill($bill, $quantity);
}
function addQuantity($quantity) {
$this->quantity += $quantity;
}
...
}
class Product {
private $name, $description, $price;
function __constructor(...) {...}
function addToBill(IBill $bill, $quantity) {
$bill->addToTotal($this->price * $quantity);
}
...
}
Tuttavia, si finisce sempre su terreno instabile. Quanto sopra richiede un metodo come addToTotal
, che introduce un invariante (il totale deve corrispondere alla somma dei prodotti dei prezzi e delle quantità dell'elemento pubblicitario), solo il tipo di cosa che "Tell, Do not Ask" dovrebbe evitare. Puoi provare a farlo senza addToTotal
: * Elimina con Bill
; ShoppingCart
tiene traccia del totale. Passa il prezzo a addItem
in aggiunta alla quantità di prodotto &; addItem
aggiorna il totale. Questo in qualche modo sconfigge lo scopo di avere classi, dato che non stai usando LineItem
o Product
per molto.Ciò aggiunge anche all'invarianza che il prezzo passato e il prezzo dato al momento della creazione del prodotto dovrebbero coincidere, anche se non lo fanno, non dovrebbero causare problemi (sarebbe semplicemente strano). * Avere addItem
un'istanza Product
e LineItem
; addItem
aggiorna il totale. Quando si aggiungono ulteriori elementi che sono stati precedentemente aggiunti, ci deve essere sia un invariante aggiuntiva che il passato-in $price
deve corrispondere al valore passato nei precedenti bandi, o addItem
semplicemente non può essere permesso di aggiungere ulteriori, elementi esistenti. * Elimina gli articoli tutti insieme. ShoppingCart
memorizza l'ID del prodotto e la quantità. Ogni chiamata a addItem
aggiorna il totale. createBill
utilizza il totale già calcolato. Anche più degli altri, questo unisce separate concerns.
Ci sono altri disegni potenziali, ma ognuno soffre di qualche tipo di problema, tipicamente relativo alla separazione degli argomenti, introducendo invarianti e aggiungere complessità. Nel complesso, l'accesso al prezzo totale di un elemento pubblicitario direttamente all'interno del metodo che calcola il totale non è solo il più semplice, ma più pulito e meno probabile che generi errori.
se un carrello della spesa contiene alist di voci, perché è male avere il carrello della spesa in grado di imparare il valore del prezzo di ogni articolo? – user12345613
in base al principio "Tell do not ask", sembra essere malvagio. – Tom
Dove hai sentito questo principio "non dire chiedere"? Non ne ho mai sentito. – xxpor