Domanda di architettura

5

Sto scrivendo un regolamento / modulo di ammissibilità. Ho 2 set di dati, uno è i dati del cliente e l'altro è i dati dei prodotti del cliente. I dati dei clienti per i dati dei prodotti dei clienti sono uno a molti.

Ora devo passare attraverso una serie di regole di idoneità per ciascuno di questi dati di prodotto del cliente. Per ogni dato sui prodotti dei clienti, posso dire che il cliente è idoneo per quel prodotto o rifiuta l'idoneità e dovrebbe passare al record del prodotto successivo.

Quindi, in tutte le regole, ho bisogno di avere accesso ai dati sui prodotti dei clienti e dei clienti (il record particolare in cui le regole vengono eseguite contro). Poiché tutte le regole possono approvare un prodotto o rifiutare un prodotto, ho creato un'interfaccia con questi 2 metodi e sto implementando questa interfaccia per tutte le regole. Sto passando i dati del cliente e i dati di un prodotto per tutte le regole (perché le regole dovrebbero essere eseguite su ogni riga di dati del prodotto del cliente). Una situazione ideale sarebbe avere i dati sui prodotti cliente e cliente disponibili per la regola invece di passarli a ciascuna regola.

Qual è il modo migliore di fare questo in termini di architettura?

Modifica: ecco cosa sto facendo

public class CustomerContract
{
    public DateTime StartDate { get; set; }
    public DateTime endDate { get; set; }
    //Other Contract related details

}
public class Customer
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string state { get; set; }
}

public class CustomerInfo
{
    public CustomerInfo(int CustomerID)
    {
        Customer = new Customer();// Get Customer from DB
        AppliedProducts = new List<CustomerProduct>();// Get the customer products by customerID
        CurrentContract = new CustomerContract();//Get the contract by CustomerID, State
        declineReasons = new List<int>();// just intailizing. the decline codes are added by rules.
    }

    public CustomerContract CurrentContract { get; set; }
    public IList<CustomerProduct> AppliedProducts { get; set; }
    public IList<int> declineReasons { get; set; }
    public Customer Customer { get; set; }
}

public class CustomerProduct
{
    public decimal AmountCharged { get; set; }
    public int DeclineReasonID { get; set; }
    public int Product { get; set; }
    public decimal DiscountApplicable { get; set; }
    public decimal AmountQuoted { get; set; }
    public decimal Tax { get; set; }
}

public interface IRule
{
    // Since we need to have access to contracts when deciding the eligibility
    CustomerProduct ExecuteRule(CustomerProduct currentproduct, CustomerInfo customerInfo);

    //when denied, 
    CustomerProduct DenyProduct(CustomerProduct currentProduct);
}

public class EligibityEngine
{
    List<IRule>  rules = new List<IRule>();
    private CustomerInfo c;

    public EligibityEngine(int CustomerID)
    {
        c = new CustomerInfo(CustomerID);
        LoadRules();
        foreach (var customerProduct in c.AppliedProducts)
        {
            ExecuteRules(customerProduct);
        }
    }

    private void ExecuteRules(CustomerProduct currentProductItem)
    {
        foreach (var rule in rules)
        {
            currentProductItem = rule.ExecuteRule(currentProductItem, c);
        }
    }

    private void LoadRules()
    {
        // add all the IRule types here
        //rules.Add();
    }
}

Quando eseguo la regola, ho passato i dati del prodotto del cliente e i dati del cliente. Devo passare il risultato di un'esecuzione di una regola all'altra. Nel modello precedente, se la regola modifica i dati nella classe customerInfo, non viene salvata a meno che non passi come riferimento.

La mia domanda è che voglio che tutte le regole abbiano accesso a questi dati senza passarli. Quindi non mi devo preoccupare di catturare la regola.

Voglio il metodo executeRule per annullare.

    
posta katie77 25.11.2011 - 00:56
fonte

3 risposte

3

Il modello di specifica sembra adatto al tuo ha bisogno di abbastanza bene. Il codice di esempio fornito riguarda appunto clienti e prodotti.

    
risposta data 25.11.2011 - 12:34
fonte
0

Non sono sicuro se questa risposta ti sarà d'aiuto, ma comunque lo faccio comunque.

Sulla base della mia comprensione di ciò che stai dicendo, ecco il mio suggerimento:

Hai già un modulo che fornisce l'accesso ai dati del cliente e hai un modulo che fornisce l'accesso ai dati del prodotto del cliente. Per ciascuno di questi moduli definire una (o più) interfacce per accedere ai dati che saranno utilizzati da almeno una regola.

Quindi crea un'interfaccia 'IRuleContext' che abbia metodi per ottenere le interfacce per l'accesso ai dati dei clienti e ai dati sui prodotti dei clienti.

Scrivi un modulo "Regole" in modo che ogni regola utilizzi un parametro di tipo "IRuleContext". Ad esempio potresti avere una classe di base astratta 'EligibilityRules' con un metodo astratto di 'bool AppliesTo (IRuleContext)'. Quindi è possibile implementare un numero di regole concrete con ciascuna di esse utilizzando un algoritmo diverso per determinare l'idoneità.

Al posto dei moduli potresti anche avere servizi, componenti, classi, ecc. Dipende dalla tecnologia che stai usando. Assicurati anche che le tue scelte soddisfino i tuoi requisiti, ad esempio un servizio web potrebbe non essere un'opzione nel tuo scenario.

    
risposta data 25.11.2011 - 04:28
fonte
0

Come sottolineato da @ian31, è necessario il modello di specifica. Una volta ho avuto un'esigenza molto simile e il design che ho sviluppato è approssimativamente il seguente:

  • Ogni regola aziendale (regole di idoneità, nel tuo caso) è stata implementata come un predicato logico o una specifica.
  • Come nel tuo caso, c'erano catene di regole, che potevano essere disposte in una congiunzione (operazione AND) o in una disgiunzione (operazione OR). In una disgiunzione, il parametro doveva essere accettato da almeno una delle regole e tale regola dovrebbe essere segnalata dal motore delle regole. In una congiunzione, il parametro dovrebbe essere accettato da tutte le regole, nel qual caso dovrebbe essere riportata la prima regola della catena.
  • C'era un'interfaccia Rule con tre implementazioni importanti: una che delegava a un predicato e le altre due implementavano i requisiti di congiunzione e disgiunzione descritti sopra.
  • C'è stato un RuleFactory che ha disposto le regole nell'ordine specificato dal cliente (cosa viene eseguito dal metodo LoadRules() nell'esempio). Questo ordine potrebbe essere facilmente modificato senza influire su altre parti dell'applicazione.

È importante notare che nessuna di queste classi ha cambiato alcun stato. Erano pure funzioni che accettavano o rifiutavano i dati.

    
risposta data 26.11.2011 - 16:53
fonte

Leggi altre domande sui tag