2013-10-22 17 views
6

come gestisco Enum senza utilizzare switch o se le istruzioni in C#?Enfasi polimorfiche per la gestione dello stato

Per esempio

enum Pricemethod 
{ 
    Max, 
    Min, 
    Average 
} 

... e ho una classe Article

public class Article 
{ 
    private List<Double> _pricehistorie; 

    public List<Double> Pricehistorie 
    { 
     get { return _pricehistorie; } 
     set { _pricehistorie = value; } 
    } 

    public Pricemethod Pricemethod { get; set; } 

    public double Price 
    { 
     get { 
      switch (Pricemethod) 
      { 
       case Pricemethod.Average: return Average(); 
       case Pricemethod.Max: return Max(); 
       case Pricemethod.Min: return Min(); 
      } 

     } 
    } 

} 

voglio evitare l'istruzione switch e renderlo generico.

Per un Pricemethod specifico chiamare un Calcolo specifico e restituirlo.

get { return CalculatedPrice(Pricemethod); } 

Quale motivo è da utilizzare qui e forse qualcuno ha una buona idea di implementazione. Ho già cercato uno schema di stato, ma non penso che sia quello giusto.

+5

prezzi dovrebbero essere 'decimal', non' double'. Usa 'double' per le grandezze fisiche come lunghezza e massa; utilizzare 'decimale' per le quantità decimali esatte. –

+0

Hai intenzione di restituire una ** raccolta ** di prezzi mutabile? Cosa impedisce al chiamante del tuo metodo di chiamare 'Cancella 'in quella lista? –

+0

Quindi lo hai taggato con _strategy-pattern_? Questa è praticamente la risposta qui ... –

risposta

11

come si gestiscono le enumerazioni senza utilizzare 0.123.o if dichiarazioni in C#?

Non è così. le enumerazioni sono solo una sintassi piacevole per scrivere const int.

considerare questo modello:

public abstract class PriceMethod 
{ 
    // Prevent inheritance from outside. 
    private PriceMethod() {} 

    public abstract decimal Invoke(IEnumerable<decimal> sequence); 

    public static PriceMethod Max = new MaxMethod(); 

    private sealed class MaxMethod : PriceMethod 
    { 
    public override decimal Invoke(IEnumerable<decimal> sequence) 
    { 
     return sequence.Max(); 
    } 
    } 

    // etc, 
} 

E ora si può dire

public decimal Price 
{ 
    get { return PriceMethod.Invoke(this.PriceHistory); } 
} 

E l'utente può dire

myArticle.PriceMethod = PriceMethod.Max; 
decimal price = myArticle.Price; 
+0

Contrassegnato come risposta corretta a causa dell'apprendimento generale di eric in questo post! – slopsucker

+0

Sembra il modello di progettazione della strategia. – Brian

+0

@Brian: Se "creare un oggetto che ha un metodo che fa ciò che vuoi" è chiamato "il modello di strategia" dagli amanti del modello, quindi sicuro, questo è il modello di strategia. Dal momento che ce n'è solo uno, è anche il modello singleton. Potrebbe anche essere il modello di fabbrica. E forse anche molti altri modelli. Non posso tenerli tutti dritti. –

5

Si potrebbe creare un interface e class ca che implementano:

public interface IPriceMethod 
{ 
    double Calculate(IList<double> priceHistorie); 
} 
public class AveragePrice : IPriceMethod 
{ 
    public double Calculate(IList<double> priceHistorie) 
    { 
     return priceHistorie.Average(); 
    } 
} 
// other classes 
public class Article 
{ 
    private List<Double> _pricehistorie; 

    public List<Double> Pricehistorie 
    { 
     get { return _pricehistorie; } 
     set { _pricehistorie = value; } 
    } 

    public IPriceMethod Pricemethod { get; set; } 

    public double Price 
    { 
     get { 
      return Pricemethod.Calculate(Pricehistorie); 
     } 
    } 

} 

Edit: un altro modo è usare un Dictionary per mappare Func s, quindi non c'è bisogno di creare classi solo per questo (questo codice è basato sul codice da Servy, che nel frattempo cancellato la sua risposta):

public class Article 
{ 
    private static readonly Dictionary<Pricemethod, Func<IEnumerable<double>, double>> 
     priceMethods = new Dictionary<Pricemethod, Func<IEnumerable<double>, double>> 
     { 
      {Pricemethod.Max,ph => ph.Max()}, 
      {Pricemethod.Min,ph => ph.Min()}, 
      {Pricemethod.Average,ph => ph.Average()}, 
     }; 

    public Pricemethod Pricemethod { get; set; } 
    public List<Double> Pricehistory { get; set; } 

    public double Price 
    { 
     get 
     { 
      return priceMethods[Pricemethod](Pricehistory); 
     } 
    } 
} 
+0

Sembra buono e funziona. Tahnk te! Ma non c'è un modo più intelligente invece di implementare tonnellate di classi che hanno 1 metodo? – slopsucker

+0

@slopsucker Ho aggiunto un esempio di questo. –

+0

Mi piace ancora la soluzione di interfaccia. Se è necessario aggiungere nuovi metodi di calcolo in futuro, non è necessario toccare la classe Article. Sì, finirai con più lezioni ma sarà più isolato e più facile da mantenere penso. La seconda soluzione è quasi la stessa di avere il tuo switch e Enums. –