L'ereditarietà è migliore o il modello di progettazione della composizione in questo scenario?

1

Progetta e implementa il registratore di cassa:

Dato un numero di elementi ti verrà richiesto di calcolare il conto totale. Gli articoli vengono addebitati in un paio di modi diversi:

  • Un determinato prezzo per ogni articolo, ad es. Le scatole di Cheerios sono $ 6,99 ciascuna

  • Un determinato prezzo in base al peso, ad es. Le mele sono $ 2,49 per libbra

  • Gli articoli possono essere messi in vendita dove potresti ricevere sconti collettivi, ad es. Compra due ne ottieni uno gratis; ne comprate quattro ne prendi uno gratis

  • I coupon sono disponibili per ottenere denaro dal conto quando l'importo totale supera una soglia, ad es. $ 5 di sconto quando spendi $ 100 o più

La mia risposta: non sono sicuro di quanto è corretto o come posso migliorarlo?!

Ho allegato il mio disegno basato su C # e il codice può essere visualizzato su link .

Ho apprezzato se potessi aiutare a capire che l'ereditarietà è migliore o la composizione. In base allo scenario indicato, la risposta deve avere le seguenti classi concrete:

  • ProductSellByQuantity.cs
  • ProductSellByQuantityInGroupSell.cs
  • ProductSellByWeight.cs

Oltre a due oggetti ShoppingCart & ShoppingCartByCoupon o potrebbe essere solo un oggetto ShoppingCart.

Il mio obiettivo è quello di rendere le competenze di progettazione OO e amp; design pattern migliore.

Fare clic per aprire in dimensioni maggiori.

    
posta Danial 14.07.2016 - 01:27
fonte

1 risposta

2

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.

    
risposta data 16.07.2016 - 03:45
fonte