Progettazione di un servizio di ordini che accetta molti tipi di ordini

0

Ho avuto qualche problema con un design che avrebbe alleviato la maggior parte, se non tutti, i problemi che ho incontrato, e mi chiedo se sia il mio design di base.

La nostra azienda accetta ordini. Accettiamo diversi tipi di ordini in base alla linea di prodotti a cui appartengono, ma tutti gli ordini condividono alcune funzionalità e proprietà. Il mio obiettivo è quello di iniettare qualsiasi ordine che implementa un'interfaccia specifica in una classe OrderRepository.

Per soddisfare queste esigenze, ho creato una classe OrderBase:

public class OrderBase {
    public string order_number {get; set;}
    public string order_type {get; set;}
    public string order_date {get; set;}
    public List<IOrderItem> order_items { get; set; }
    public virtual bool Validate();
}

Ho creato un'interfaccia che simula la classe base in modo da poter utilizzare la classe base esattamente come quella ... la funzionalità di base per un ordine.

public interface IOrder {
    string order_number {get; set;}
    string order_type {get; set;}
    string order_date {get; set;}
    List<IOrderItem> order_items { get; set; }
    bool Validate();
}

Un tipo di ordine è implementato come tale:

public class TXOrder : OrderBase, IOrder {

    // Specific to TXOrder only
    public bool isOnHold {get; set; }

    public override bool Validate() {
        // Enter TXOrder-specific validations here.
        return base.Validate();
    }
}

TXOrder eredita la classe base, ottenendo tutte le proprietà e i metodi e l'interfaccia implementata è soddisfatta dalle proprietà e dai metodi della classe base. Al momento funziona con ModelBinders che si associano all'oggetto corretto per i dati in arrivo.

Il repository ha questo aspetto:

interface IRepository<T, U>
        where U : IParameters
    {
        T SelectSingle(long id);
        List<T> Select(U parameters);
        T Insert(T entity);
        T Update(T entity);
        T Delete(T entity);
    }

public  class OrderRepository: IRepository<IOrder, OrderParameters> {}

Se hai bisogno dei dettagli cruenti del OrderRepository, non esitare a chiedere. Accetta qualsiasi ordine che io possa lanciare di tipo IOrder. Questo è il punto chiave da portare via.

Questo è un modello che può continuare a funzionare a lungo termine mentre aggiungo funzionalità specifiche per ogni tipo di ordine? C'è un altro modello che posso guardare?

    
posta jlrolin 26.09.2016 - 19:36
fonte

2 risposte

1

Penso che dovresti smettere di usare la classe base e il tipo di ordine e andare semplicemente con le interfacce. Definirei interfacce che rappresentano le varie caratteristiche che gli ordini possono avere e implementare le interfacce che hanno senso per ogni tipo di ordine. In questo modo la logica si basa su un insieme di proprietà e metodi disponibili anziché su un valore del tipo di ordine.

Ad esempio se hai definito interfacce come questa

public interface IOrder
{
    Int OrderId { get; set; }
    DateTime OrderDate { get; set; }
}

public interface IValidatable
{
    void Validate();
}

public interface IDiscountable
{
    void Discount();
}

Quindi puoi creare diversi tipi di ordine come questo

public class OrderA: IOrder, IValidatable
{ ... etc ... }

public class OrderB: IOrder, IDiscountable
{ ... etc ... }

public class OrderC: IOrder
{ ... etc ... }

Quando passi un IOrder al tuo gestore ordini invece di avere una logica basata sul tipo di ordine, puoi basare la tua logica sul fatto che l'ordine implementa un'interfaccia specifica, ad esempio

public void Process(IOrder order)
{
    var validatable = order as IValidatable;
    If (validatable != null)
        validatable.Validate();

    var discountable = order as IDiscountable;
    if (discountable != null)
        discountable.Discount();
}
    
risposta data 07.12.2016 - 09:56
fonte
0

Penso che non ti serva affatto l'interfaccia.
Se la classe OrderBase viene utilizzata solo come contenitore della funzionalità di base, rendila astratta

public abstract class OrderBase 
{
    public virtual string order_number {get; set;}
    public virtual string order_type {get; set;}
    public virtual string order_date {get; set;}
    public virtual List<IOrderItem> order_items { get; set; }
    public virtual bool Validate();
}

E la classe derivata erediterà solo la classe astratta senza interfaccia.

Se vuoi mantenere le interfacce e la logica di base, allora crea un'interfaccia per l'implementazione della classe base

public class OrderBase : IOrder
{
    public string order_number {get; set;}
    public string order_type {get; set;}
    public string order_date {get; set;}
    public List<IOrderItem> order_items { get; set; }
    public virtual bool Validate();
}

La classe specifica erediterà solo dalla classe base

public class TXOrder : OrderBase
{
    public bool isOnHold {get; set; }

    public override bool Validate() 
    {
        // Specific validation
    }
}

Ma ricorda che quando passi diversi tipi di ordine al metodo "gestore" come classe o interfaccia di base, non avrai accesso alle proprietà o ai metodi specifici.

Puoi usarli solo con il metodo che hai sovrascritto.

public override bool Validate() 
{
    if(isOnHold == true) return false;
}

Questo approccio funzionerà finché non avrai bisogno in qualche modo di accedere alle proprietà o ai metodi specifici da parte del consumatore di ordini.

    
risposta data 08.10.2016 - 04:34
fonte