Over-Engineering precoce
Ad esempio, asserisco che non hai bisogno di nessuno di questi interface
s. Se necessario in seguito, fallo in un secondo momento.
Un interface
(il tipo di parola chiave C #) serve per dare un comportamento comune alle classi non correlate e quindi gestire gli oggetti in modo polimorfico.
Pensa più attentamente a ciò che costituisce una classe più specifica. Pensa a cosa è un carrello della spesa. Un "carrello della spesa coupon" è un tipo più specifico di carrello o è semplicemente un attributo in un carrello?
Pensa con più attenzione a come le cose funzionano insieme, in contrasto con il vedere tutto come bit separati e distinti. Un coupon è una parte logica del calcolo di un prezzo. GetPrice
è semplicemente un metodo "grunt" necessario in una classe di prodotto.
"groupale" è uno sconto sul volume. Questo è lo stesso concetto di un coupon. Entrambi sono sconti. Detto in un altro modo, sono semplicemente aggiustamenti al prezzo. Pertanto sono parte integrante del calcolo del costo. Non sono classi.
Troppo interface
Il codice alle interfacce non all'implementazione non significa rendere tutto una (parola chiave C #) interface
. Qualsiasi insieme di metodi pubblici di classe è un'interfaccia.
Implementare interfacce invece di ereditare da una classe astratta ti imposta per molte implementazioni ridondanti.
Questa è una grottesca (mi dispiace) errata applicazione del principio Interface segregation
. Non riesco a vedere in che modo ISell
si giustifica come%% distinto%. Non vedo i riferimenti di interface
passati in giro. ISell
sembra semplicemente appartenere naturalmente a un oggetto GetPrice()
; dove il suo significato è più chiaro all'interno di una classe funzionale.
Idem per il carrello degli acquisti.
Peso, quantità astratta
Sottratto, sospetto strongmente che le classi multiple ProductXXX
siano racchiuse in una sola.
Questi sono semplicemente valori. E questi valori sono usati nel calcolo allo stesso modo, cioè ProductSellBy...
Il fatto che GetPrice() * Quantity()
rappresenti cose o peso numerabili può essere catturato da una proprietà separata. Hai già ottenuto un quantity
per questo, crea una proprietà di quel tipo nella classe enum
.
Questa astrazione elimina la motivazione per le molte interfacce e classi e il tuo diagramma si ridurrà di più della metà credo.
ASCIUGARE i metodi ridondanti
Crea una classe Product
per abstract
s.
Product
"Con coupon" non ha senso come sottoclasse del carrello della spesa. Un coupon è semplicemente un adeguamento al calcolo del prezzo.
Come sopra, elimina quei ShoppingCart coupon
s e crea una classe interface
se devi sottoclasse abstract
.
E quando ci pensi, un coupon non è davvero un caso speciale. Un costo è scontato con coupon allo stesso modo per qualsiasi articolo, presumo. In modo che lo sconto possa essere integrato nel calcolo del prezzo. Questo è soddisfatto dal valore predefinito del coupon che non rappresenta uno sconto.