Design Pattern per l'importazione di dati di vari tipi di sorgenti e vari tipi di destinazione

14

Devo progettare e creare uno script di importazione (in C #) in grado di gestire quanto segue:

  • legge i dati da varie fonti (XML, XSLX, CSV)
  • verifica i dati
  • scrivi i dati su vari tipi di oggetto (cliente, indirizzo)

I dati verranno da un certo numero di fonti, ma una fonte avrà sempre un formato di importazione (csv, xml, xslx). I formati di importazione possono variare da sorgente a fonte. Nuovi formati di importazione possono essere aggiunti in futuro. I tipi di oggetto di destinazione sono sempre gli stessi (cliente, indirizzo e altro).

Ho pensato di utilizzare i farmaci generici e ho letto qualcosa sul modello di fabbrica, ma sono un noob piuttosto grande in questo settore, quindi qualsiasi consiglio è più che benvenuto.

Qual è uno schema di progettazione appropriato per risolvere questo problema?

    
posta jao 22.08.2013 - 18:27
fonte

4 risposte

11

Stai andando fuori bordo con concetti di fantasia troppo presto. Generici: quando vedi un caso usali, ma altrimenti non preoccuparti. Modello di fabbrica: troppa flessibilità (e aggiunta confusione) per questo ancora.

Mantengalo semplice. Utilizza le pratiche fondamentali.

  1. Prova ad immaginare le cose comuni tra fare una lettura per XML, una lettura per CSV qualunque. Cose del genere, prossimo record, riga successiva. Poiché è possibile aggiungere nuovi formati, provare a immaginare la comunanza che il formato da determinare avrebbe con quelli noti. Utilizza questa comunanza e definisci un'interfaccia o un contratto a cui tutti i formati devono attenersi. Sebbene aderiscano al terreno comune, potrebbero avere tutte le loro regole interne specifiche.

  2. Per convalidare i dati, provare a fornire un modo per inserire facilmente nuovi o nuovi blocchi di codice di convalida. Quindi, ancora una volta, prova a definire un'interfaccia in cui ogni validatore, responsabile di un particolare tipo di costruzione dei dati, aderisce a un contratto.

  3. Per creare le costruzioni di dati, probabilmente sarai costretto da chiunque disegni gli oggetti di output suggeriti più di ogni altra cosa. Cerca di capire quale sia il passo successivo per gli oggetti dati e quali sono le ottimizzazioni che puoi ottenere conoscendo l'utilizzo finale. Ad esempio, se si conoscono gli oggetti che verranno utilizzati in un'applicazione interattiva, si potrebbe aiutare lo sviluppatore di tale app fornendo "sommazioni" o conteggi degli oggetti o altri tipi di informazioni derivate.

Direi che la maggior parte di questi sono modelli di modelli o modelli di strategia. L'intero progetto sarebbe un modello adattatore.

    
risposta data 23.08.2013 - 04:06
fonte
9

La cosa ovvia è applicare Pattern di strategia . Avere una classe di base generica ReadStrategy e per ogni formato di input una sottoclasse come XmlReadStrategy , CSVReadStrategy ecc. Ciò consentirà di modificare l'elaborazione dell'importazione indipendentemente dall'elaborazione della verifica e dall'elaborazione dell'output.

A seconda dei dettagli potrebbe essere anche possibile mantenere la maggior parte delle parti generiche dell'importazione e scambiare solo parti dell'elaborazione dell'input (ad esempio, la lettura di un record). Questo può portare a modello Metodo modello .

    
risposta data 22.08.2013 - 19:10
fonte
7

Un modello adatto per un'utilità di importazione che potrebbe essere necessario estendere in futuro sarebbe utilizzare MEF - puoi mantenere basso l'uso della memoria caricando il convertitore necessario al volo da una lista pigra, creare importazioni MEF che sono decorato con attributi che aiutano a selezionare il convertitore giusto per l'importazione che stai cercando di eseguire e fornisce un modo semplice per separare le diverse classi di importazione.

Ogni parte MEF può essere costruita per soddisfare un'interfaccia di importazione con alcuni metodi standard che convertono una riga del file di importazione nei dati di output o sovrascrivono una classe base con la funzionalità di base.

MEF è un framework per la creazione di un'architettura plug-in - il modo in cui Outlook e Visual Studio sono costruiti, tutte quelle deliziose estensioni in VS sono parti MEF.

Per creare un'app per MEF (Managed Extensability Framework), includi un riferimento a System.ComponentModel.Composition

Definisci interfacce per spec out su cosa farà il convertitore

public interface IImportConverter
{
    int UserId { set; }        
    bool Validate(byte[] fileData, string fileName, ImportType importType);
    ImportResult ImportData(byte[] fileData, string fileName, ImportType importType);
}

Può essere usato per tutti i tipi di file che vuoi importare.

Aggiungi attributi a una nuova classe che definiscono ciò che la classe "Esporta"

[Export(typeof(IImportConverter))]
[MyImport(ImportType.Address, ImportFileType.CSV, "4eca4a5f-74e0")]
public class ImportCSVFormat1 : ImportCSV, IImportConverter
{
 ...interface methods...
}

Questo definirà una classe che importerà i file CSV (di un particolare formato: Format1) e ha degli attributi personalizzati che impostano i metadati degli attributi di esportazione MEF. Lo ripeteresti per ogni formato o tipo di file che desideri importare. Puoi impostare attributi personalizzati con una classe come:

[MetadataAttribute]
[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class ImportAttribute : ExportAttribute
{
    public ImportAttribute(ImportType importType, ImportFileType fileType, string customerUID)
        : base(typeof(IImportConverter))
    {
        ImportType = importType;
        FileType = fileType;
        CustomerUID = customerUID;
    }

    public ImportType ImportType { get; set; }
    public ImportFileType FileType { get; set; }
    public string CustomerUID { get; set; }
}

Per utilizzare effettivamente i convertitori MEF è necessario importare le parti MEF che crei quando viene eseguito il codice di conversione:

[ImportMany(AllowRecomposition = true)]
protected internal Lazy<IImportConverter, IImportMetadata>[] converters { get; set; }
AggregateCatalog catalog = new AggregateCatalog();

catalog raccoglie le parti da una cartella, il valore predefinito è la posizione dell'app.

converters è un elenco pigro delle parti MEF importate

Quindi quando sai quale tipo di file vuoi convertire ( importFileType e importType ) ottieni un convertitore dall'elenco delle parti importate in converters

var tmpConverter = (from x in converters
                    where x.Metadata.FileType == importFileType
                    && x.Metadata.ImportType == importType 
                    && (x.Metadata.CustomerUID == import.ImportDataCustomer.CustomerUID)
                    select x).OrderByDescending(x => x.Metadata.CustomerUID).FirstOrDefault();

if (tmpConverter != null)
{
     var converter = (IImportConverter)tmpConverter.Value;
     result = converter.ImportData(import.ImportDataFile, import.ImportDataFileName, importType);
....
}

La chiamata a converter.ImportData utilizzerà il codice nella classe importata.

Potrebbe sembrare un sacco di codice e potrebbe volerci un po 'di tempo per capire cosa sta succedendo, ma è estremamente flessibile quando si tratta di aggiungere nuovi tipi di convertitore e può persino permetterti di aggiungerne di nuovi durante il runtime.

    
risposta data 22.08.2013 - 20:17
fonte
0

What is an appropriate design pattern to solve this problem?

Gli idiomi C # implicano l'uso del framework di serializzazione integrato per fare ciò. Annoti gli oggetti con i metadati, quindi istanzia un serializzatore diverso che utilizza tali annotazioni per estrarre i dati da inserire nella forma corretta o viceversa.

I moduli Xml, JSON e binari sono i più comuni, ma non sarei sorpreso se altri esistessero già in un bel modulo compresso da consumare.

    
risposta data 22.08.2013 - 19:17
fonte

Leggi altre domande sui tag