Compila i campi o restituisci l'oggetto

6

Che cosa è meglio fare in questo tipo di scenario: popola i campi o restituisci un oggetto?

La situazione è la seguente: sto facendo calcoli per trovare i prezzi (tasse inc., tasse escluse, sconti ecc.) di un prodotto. C'è qualche consiglio o ci sono delle linee guida su come gestire un valore di ritorno?

Compila campi:

public class ProductPrice
{
    public int BasePrice;
    public int IncTax;
    public int ExTax;
    // ...

    public void GetPricesForProduct(int ProductID)
    { /* Populate fields based on results */ }
}

Oggetto restituito:

public class PriceCalculator
{
    public ProductPrice GetPricesForProduct(int ProductID)
    { /* Populate object fields and return object */ }
}
public class ProductPrice
{
    public int BasePrice;
    public int IncTax;
    public int ExTax;
}

Non sono sicuro che mi piaccia il primo metodo, perché il tipo di ritorno void non chiarisce cosa succede quando il metodo viene eseguito. Tuttavia, restituire un oggetto risulta in una classe che non ha funzionalità.

    
posta Andy Hunt 19.04.2012 - 14:52
fonte

9 risposte

8

Hai ragione a preferire il secondo metodo. Il primo metodo potrebbe ingombrare facilmente una classe con i membri che meglio si adattino a un oggetto che rappresenta quei valori.

Ancora meglio, aggiungi un metodo a ProductPrice che esegue il calcolo e modifica "PriceCalculator" a "PriceFetcher" che ottiene semplicemente i valori non elaborati e crea un'istanza ProductPrice.

public class PriceFetcher
{
    public ProductPrice GetPricesForProduct(int ProductID)
    { /* Populate object fields and return object */ }
}
public class ProductPrice
{
    public int BasePrice;
    public int IncTax;
    public int ExTax;

    public float GetPrice() 
    { /* Perform calculation on given data */ }
}

Questo metodo ha il vantaggio aggiunto che l'oggetto determina come viene calcolato il prezzo e non il metodo che recupera i dati, consentendo di eseguire operazioni più complesse in seguito con classi derivate di ProductPrice e di istanziarli utilizzando una factory in PriceFetcher.

    
risposta data 19.04.2012 - 15:02
fonte
2

Il secondo approccio mi sembra migliore. Dissocia il prezzo dal prodotto.

La classe potrebbe non avere alcun comportamento in questo momento, ma potrebbe essere in futuro. Anche se non lo fosse, non significa che non ha una funzione: contiene dati che non appartengono alla classe del prodotto.

    
risposta data 19.04.2012 - 15:02
fonte
2

Bene, l'uso di void non ha senso in quanto è in conflitto con il nome della funzione. Se hai qualcosa chiamato get*** , mi aspetto che restituisca un oggetto (o una primitiva). Il secondo approccio sembra essere più corretto in quanto il tuo PriceCalculator è in realtà il programma main (almeno è così che appare in questo banale esempio). Vorrei ridenominare la funzione in GetPricesForProductById in quanto è ciò che stai facendo, non ottenere prezzi da un Product

    
risposta data 19.04.2012 - 15:03
fonte
1

la seconda opzione (il modello factory) è migliore (aggiungi l'id all'oggetto restituito e rendilo immutabile per il completamento ma è tutto ciò che cambierei)

quando hai un metodo chiamato get* ci si aspetta che restituisca qualcosa, ma anche calculatePricesForProduct non ha quello che dovrebbe essere perché si inizia da un oggetto diverso e lo si sovrascrive con il nuovo prodotto. Questo tipo di oggetti mutabili è un problema con cui lavorare in sicurezza (eseguirne una copia ovunque sia necessario per utilizzarlo) a meno che non ne abbia pianificato completamente l'uso

    
risposta data 19.04.2012 - 15:07
fonte
1

Il secondo è chiaramente migliore. Immagina di chiamare GetPricesForProduct una seconda volta con un ID diverso prima di aver copiato tutti i campi. Per me la prima versione è un anti-pattern. Non farlo mai.

    
risposta data 19.04.2012 - 15:43
fonte
1

Secondo metodo (per tutti i motivi già forniti) e:

  • rende PriceCalculator un'interfaccia; un giorno potresti averne bisogno per i consumatori, uno per i clienti business, uno per i clienti governativi, uno per i clienti internazionali (UE), uno per i clienti internazionali (al di fuori dell'UE) ecc., quindi implementerai calcolatori diversi e userai quello hai bisogno di

  • rende immutabili i campi in ProductPrice; forse è meglio rendere ProductPrice un'interfaccia con alcuni getter (attributi di sola lettura in C #); perché potresti voler riutilizzare quegli oggetti, ad esempio memorizzandoli nella cache o utilizzando il prezzo di un prodotto per più di un prodotto (sì, il mouse rosso costa esattamente tanto quanto il mouse verde, il mouse giallo e il mouse blu)

risposta data 19.04.2012 - 17:00
fonte
1

Non so perché PriceCalculator è una classe a sé stante. Il valore del prezzo calcolato è una proprietà che appartiene logicamente alla classe ProductPrice. Il calcolo del prezzo non è un'utilità o un aiuto dipende strettamente dal ProductPrice e (dovrebbe) essere incapsulato in quella classe. Di conseguenza, PriceCalculator dovrebbe essere il metodo CaculateProductPrice () all'interno della classe ProductPrice (o della classe Product). Un altro motivo è che non si desidera mai istanziare ProductPrice e PriceCalculator separatamente. In effetti, probabilmente non avrai mai bisogno di creare un oggetto da PriceCalculator da solo.

Modifica: ha aggiunto il testo (o la classe del prodotto), poiché non sono pienamente a conoscenza delle proprietà e delle condizioni in e tra prodotto e prodotto.

    
risposta data 19.04.2012 - 16:09
fonte
1

Pensando a come funzionano i prezzi ea cosa potrebbe succedere in futuro, consiglierei: -

Una singola classe "productPrice".

La classe dovrebbe avere uno o più metodi getPrice

public int getPrice(getPrice.Type priceType) {}

public int getPrice(getPrice.Type priceType, int offerCode) {} 

public int getPrice(getPrice.Type priceType, int discount) {} 

Dove "priceType" è un ennum che definisce il tipo di prezzo desiderato.

In una grande situazione di vita reale puoi offrire prezzi diversi a seconda di un vasto numero di variabili: -

  • Canale - es. Il prezzo web può differire dall'ordine postale
  • Offerte speciali - i clienti che hanno partecipato a una fiera, che hanno visitato un determinato sito Web, possono ottenere un codice di offerta che ottiene loro un prezzo speciale.
  • Fatturato: i clienti che acquistano molto ricevono un prezzo migliore.
  • Nuovi clienti - offerte introduttive per i nuovi clienti.
  • Posizione: il marketing potrebbe essere indirizzato a una determinata regione o città.
  • Segmento di mercato - Il marketing potrebbe spingere per aumentare le vendite a un tipo specifico di cliente.
risposta data 23.04.2012 - 03:34
fonte
0

Sarò un po 'contrario e dirò che il primo metodo è migliore, SE apporti questa modifica:

La tua funzione GetPricesForProduct () dovrebbe essere la CONSTRUCTOR per ProductPrice.

Perché un oggetto ProductPrice senza particolari prodotti non significa nulla; non è inizializzato correttamente

    
risposta data 19.04.2012 - 18:27
fonte

Leggi altre domande sui tag