come creare una struttura di classi generica

3

Ho un requisito in cui l'utente seleziona un ReportType da un menu a discesa e fa clic sul pulsante di download. In base al tipo scelto, il sistema dovrebbe generare un report. Al momento ho solo un tipo di rapporto che è QuoteReport. In futuro avrò altri tipi di report come PolicyReport, ClaimReport. Al momento non ho idea di quali saranno i campi dati in questi report, ma "Avranno tutti almeno alcune proprietà comuni" come ID e Indirizzo

 public class QuoteReport
 {
  public String DeviceType { get; set; }
  public String ProductName { get; set; }
  public String Description { get; set; }
  public String ID { get; set; }
  public String Address { get; set; }     
 }

Ora quello che sto facendo è inviare tipo di rapporto e parametri per compilare il rapporto e ho creato un caso di scambio per individuare il tipo di rapporto selezionato.

public string PrepareReport(string selectedReport, List<int> Ids)
{
string response = string.Empty;
try
{
    ReportTypeEnum reportTypeEnum;
    if (Enum.TryParse(selectedReport, out reportTypeEnum))
    {
        switch (reportTypeEnum)
        {
            case ReportTypeEnum.QuoteReport:
                response = CreateReportData(Ids,response);
                break;
            default:
                break;
        }
    }
}
catch (Exception exc)
{
    handleException(DOWNLOAD_REPORT, exc);
}
return response;
}

Il mio metodo CreateReportData riempie i campi della classe QuoteReport da wcf.

 public string CreateReportData(List<int> Ids, string response)
{
List<QuoteReport> quoteReportList = new List<QuoteReport>();            
foreach (var Id in Ids)
{
    dynamic dynamicEntity;
    List<string> devices = proxy.GetData(Id);
    for (int i = 0; i < devices.Count; i++)
    {
        QuoteReport quoteReport = new QuoteReport();
        dynamicEntity = JObject.Parse(devices[i]);
        quoteReport.Type = dynamicEntity.DeviceTypeString;
        quoteReport.ProductName = dynamicEntity.ProductName;
        quoteReport.Description = dynamicEntity.Desc;
        quoteReport.ID = dynamicEntity.ID;
        assetReport.Address = dynamicEntity.Address;
         quoteReportList.Add(quoteReport );

    }
}
response = JsonConvert.SerializeObject(quoteReportList );
return response;
}

Ora sono perplesso su come posso rendere il mio codice più generico. O dovrei usare alcuni schemi di progettazione come Factory per rendere il codice adattabile alle esigenze future? Come posso rendere generico il metodo CreateReportData in modo che accetti qualsiasi tipo di classe e lo riempia?

    
posta pankaj 23.01.2017 - 08:45
fonte

2 risposte

4

Il modello di progettazione che richiede attenzione qui quando dici "adattabile per esigenze future" è il modello di strategia . Potresti eliminare lo switch, l'enum e probabilmente PrepareReport se facendo clic su questo pulsante di download ha eseguito questo codice:

selectedReport.CreateReport(List<int> Ids);

Quale codice eseguito dipende interamente dall'oggetto attualmente impostato in selectedReport . È possibile creare un numero qualsiasi di tipi di report in questo modo senza dover modificare alcun codice esistente tranne il codice che offre l'elenco dei tipi di report nella GUI. Il modo in cui lo hai ogni nuovo tipo deve essere aggiunto in almeno due posti.

Questo cambiamento è in realtà uno dei refactoring originali di Martin Fowler: Sostituisci condizionale con polimorfismo .

Puoi implementarlo in molti modi diversi, ma il modello di strategia è un buon modo per ottenere il polimorfismo. L'idea è di creare codice che non richieda modifiche in molti punti per aggiungere un nuovo rapporto.

    
risposta data 23.01.2017 - 13:36
fonte
0

Due cose di cui preoccuparsi: stato e comportamento. Parliamo innanzitutto dello stato.

Se prendiamo la tua semplice spiegazione inglese, posso tradurre in codice.

All reports will have some common properties, like ID and Address

abstract class BaseReport
{
    string ID { get; set; }
    Address Address { get; set; }
}

In future I will have other report types like PolicyReport,ClaimReport.

class PolicyReport: BaseREport
{
    //Define additional fields here
}

class ClaimReport: BaseReport
{
    //Define additional fields here
}

Si noti che nelle classi che definiscono report specifici, non è necessario dichiarare ID e indirizzo, perché sono già presenti come membri della classe base.

Quindi, questo è lo stato. Che dire del comportamento?

Una cosa che devi decidere è se questi oggetti saranno in grado di recuperare i propri dati. Potresti scrivere codice all'interno di ognuno di essi che ottiene i dati necessari per popolare il rapporto:

abstract class BaseReport
{
    abstract DataTable GetData();
    abstract void Render(DataTable data);

    public void Create()
    {
        var data = GetData(); 
        Render(data);
    }
}

quindi nel rapporto specifico che scriverebbe

public class PolicyReport : BaseReport
{
    override public DataTable GetData()
    {
        var client = new SqlClient();
        return client.RunQuery("SELECT * FROM Policy");
    }

    override public void Render(DataTable data)
    {
        //Draw the report somehow
    }
}

Quindi per creare un rapporto sui criteri che avresti eseguito:

var policyReport = new PolicyReport();
policyReport.Create();

Ma se vuoi separare il recupero dei dati dal codice di formattazione, forse preferisci usare qualcosa come Pattern visitatori .

    
risposta data 24.01.2017 - 03:42
fonte

Leggi altre domande sui tag