Separazione delle preoccupazioni durante la creazione di un concetto generico di "articolo carrello"

1

Impostazione abbastanza semplice: ho ottenuto un Cart e il carrello ha Items . Ho molti tipi diversi di "prodotti" che non possono davvero essere riassunti in una cosa o anche in un antenato comune, quindi ho deciso invece di creare semplicemente una rappresentazione del prodotto come CartItem , che contiene tutte le informazioni dal prodotto necessarie per effettuare la vendita.

Ecco dove arriva la domanda. Potrei gestirlo in tre modi che vedo. Per questi esempi diremo semplicemente che ho due tipi di "prodotti": Widget s e Gizmo s. Ancora una volta, queste due cose sono così diverse che non ha senso che possano ereditare da qualsiasi classe base.

1) Sia Widget che Gizmo hanno la capacità di creare un Cart Item per rappresentare se stessi, ma ciò richiede sia la conoscenza di CartItem che qualsiasi modifica a CartItem mi imporrà di tocca sia Widget che Gizmo (non ideale, ovviamente)

2) Un CartItem può creare se stesso da un Widget o un Gizmo . Questo sarebbe essenzialmente un pattern factory e richiederebbe CartItem di avere conoscenza sia di Widget che di Gizmo . Questo è meglio del # 1 in quanto non devo apportare modifiche ad ogni tipo di "prodotto" se cambio CartItem , ma io do devo ricordare che se cambio un particolare " prodotto ", quindi devo cambiare il metodo di fabbrica di CartItem per quello. (ancora non ideale, perché Murphy dice che dimenticherò).

3) Usa qualcosa come il controller come "colla". WidgetController e GizmoController avranno AddToCart azioni che traducono Widget o Gizmo , rispettivamente, in CartItem . Questo in realtà presenta gli stessi problemi del # 1, in quanto se CartItem cambia, devo aggiornare tutti i controller "del prodotto" e in effetti si mescola nei problemi del n. 2, nel senso che devo ricordare di mantenere sempre questa mappatura se qualcosa su entrambi i lati cambia. Tuttavia, sembra più simile a un lavoro per il controller: è orientato a trattare con più tipi, mentre sembra semplicemente sbagliato mescolare i tipi a livello di modello.

4) Tre che riesco a vedere; # 4 sarebbe qualcosa che devo ancora considerare che uno di voi individui gentili potrebbe accennare a suggerire.

Sono aperto a qualsiasi commento qui. Se mi manca qualcosa di completamente ovvio, sentitevi liberi di chiamarmi un idiota e indicare quanto sia grande un idiota. Mi piace sentirmi stupido; è quando sto imparando;).

    
posta Chris Pratt 06.04.2013 - 05:40
fonte

4 risposte

2

L'ovvia soluzione semplice è avere sia Gizmo che Widget implementare ICartItem , che sarebbe un'interfaccia che contiene esattamente ciò che serve per rappresentare qualcosa in un carrello, e niente di più (per esempio, prezzo unitario , quantità, unità, descrizione). Gizmo e Widget potrebbero avere modi radicalmente diversi di arrivare a questi, a patto che implementino correttamente l'interfaccia.

L'evidente svantaggio con l'ovvia soluzione semplice è che ora sia Gizmo che Widget devono sapere alcune cose sui carrelli degli acquisti, che violano il principio di Responsabilità Unica. Se ritieni che ciò stia accadendo, valuta la possibilità di suddividere le cose: Gizmo e Widget sono completamente indipendenti, senza alcuna funzionalità condivisa di sorta; GizmoCartItem e WidgetCartItem implementano entrambe l'interfaccia ICartItem e sanno come gestire un Gizmo o un Widget come articolo del carrello; il carrello della spesa si occupa ancora rigorosamente di ICartItem s; e probabilmente vorrai una sorta di fabbrica che crei ICartItem s per Gizmo se Widget s in modo da non dover mai toccare direttamente le classi di colla. Con questo design, Gizmo non sa nulla di carrelli della spesa, né di Widget; il carrello della spesa non sa nulla di Gizmos; e la colla del carrello fa sapere abbastanza su entrambi i Gizmos e i carrelli della spesa per interfacciarli.

    
risposta data 06.04.2013 - 14:31
fonte
4

Mi sento davvero male come se volessi un'interfaccia ICartItem. Se è necessario modificare il contratto, ogni singolo implementer interromperà la build fino a quando non saranno tutti aggiornati in modo appropriato, quindi ti manterrà onesto.

Se sei in una lingua digitata dinamicamente, tuttavia, direi la stessa cosa, ad eccezione del fatto che un'interfaccia esiste per essere un contratto che mantiene gli oggetti onesti, nelle lingue dinamicamente tipizzate l'unica tecnica che hai a disposizione per mantenere onesti i tuoi oggetti è test di run-time, quindi scriverò alcuni test che assicurano che tutti gli oggetti che prevedete di implementare nell'interfaccia ICartItem realizzino effettivamente tutte le parti con le firme previste. Se sei in una lingua tipizzata in stile statico, però ottieni queste garanzie gratuitamente in fase di compilazione.

Penso che tutti e tre che stai citando stiano pensando troppo alla struttura degli oggetti comuni, quando i contratti comuni sono più leggeri pur mantenendo maggiori garanzie in fase di compilazione. Gli oggetti comuni sono per quando hai una funzionalità condivisa che non vuoi ripetere, ma nella tua situazione stai rivendicando zero funzionalità condivise logiche. Vuoi solo trattare diversi tipi come lo stesso tipo, questa è la definizione di polimorfismo e l'intero scopo delle interfacce.

    
risposta data 06.04.2013 - 07:17
fonte
2

Dipende un po 'da quanto è complesso creare un CartItem , ma vorrei andare con l'opzione (1), o l'opzione (1) che delega la creazione effettiva ad un'altra classe.

(2) viola il principio open-closed - se devi aggiungere un nuovo terzo tipo di prodotto Gadget dovresti cambiare CartItem in modo che possa creare se stesso anche da Gadget .

(3) è meno riutilizzabile di averlo nel modello. Se hai bisogno di un nuovo controller che offra una visualizzazione diversa, verrai tentato di chiamare metodi dall'altro WidgetController solo per creare un CartItem .

Inoltre, non penso che le tue obiezioni al n. 1 siano giustificate. Penso che sia naturale che un prodotto sappia come creare un CartItem di se stesso. Ma se pensi che sembri puzzolente, forse è più naturale avere un metodo addToCart(cart, quantity) in Widget e Gizmo invece, nascondendo dove viene creato il CartItem effettivo?

    
risposta data 06.04.2013 - 08:46
fonte
1

Preferirei l'opzione (2) ma mettere la fabbrica in una classe separata. In questo modo puoi evitare di inquinare i tuoi prodotti con informazioni su come realizzare cartelli. Se il prodotto cambia la fabbrica non è necessario cambiare come hai menzionato. Solo se cambia la costruzione del cartitem, che è esattamente ciò che la fabbrica è per.

    
risposta data 06.04.2013 - 09:45
fonte

Leggi altre domande sui tag