Pola Desain untuk impor data dari berbagai jenis sumber dan ke berbagai jenis tujuan

14

Saya harus merancang dan membuat skrip impor (dalam C #) yang dapat menangani hal berikut:

  • membaca data dari berbagai sumber (XML, XSLX, CSV)
  • Memverifikasi data
  • tulis data ke berbagai jenis objek (pelanggan, alamat)

Data akan berasal dari sejumlah sumber tetapi sumber akan selalu memiliki satu format impor (baik csv, xml, xslx). Format impor dapat bervariasi dari sumber ke sumber. Format impor baru dapat ditambahkan di masa mendatang. Jenis objek tujuan selalu sama (pelanggan, alamat, dan beberapa lainnya).

Saya sudah berpikir tentang menggunakan obat generik dan saya membaca sesuatu tentang pola pabrik tetapi saya seorang noob yang cukup besar di bidang ini sehingga saran apa pun lebih dari sambutan.

Apa pola desain yang tepat untuk mengatasi masalah ini?

jao
sumber
Tetap sederhana.
NoChance

Jawaban:

11

Anda akan berlebihan dengan konsep mewah terlalu cepat. Generik - ketika Anda melihat kasing menggunakannya, tetapi sebaliknya jangan khawatir. Pola pabrik - terlalu banyak fleksibilitas (dan menambahkan kebingungan) untuk ini.

Tetap sederhana. Gunakan praktik mendasar.

  1. Coba bayangkan hal-hal umum antara melakukan membaca untuk XML, membaca untuk CSV apa pun. Hal-hal seperti, catatan berikutnya, baris berikutnya. Karena format baru dapat ditambahkan, coba bayangkan kesamaan bahwa format yang akan ditentukan dengan yang dikenal. Gunakan kesamaan ini dan tentukan 'antarmuka' atau kontrak yang harus dipatuhi semua format. Meskipun mereka berpegang pada landasan bersama, mereka semua mungkin memiliki aturan internal khusus mereka.

  2. Untuk memvalidasi data, cobalah memberikan cara untuk dengan mudah memasukkan blok kode validator baru atau berbeda. Jadi sekali lagi, cobalah untuk mendefinisikan antarmuka di mana setiap validator, yang bertanggung jawab untuk jenis konstruksi data tertentu mematuhi kontrak.

  3. Untuk membuat konstruksi data Anda mungkin akan dibatasi oleh siapa pun yang mendesain objek output yang disarankan lebih dari apa pun. Cobalah untuk mencari tahu apa langkah selanjutnya untuk objek data, dan apakah ada optimasi yang dapat Anda lakukan dengan mengetahui penggunaan akhir. Misalnya jika Anda tahu objek akan digunakan dalam aplikasi interaktif, Anda dapat membantu pengembang aplikasi itu dengan memberikan 'penjumlahan' atau jumlah objek atau jenis informasi turunan lainnya.

Saya akan mengatakan sebagian besar adalah pola Templat atau pola Strategi. Seluruh proyek akan menjadi pola Adaptor.

Andyz Smith
sumber
+1, terutama untuk paragraf pertama (dan menyenangkan melihat Anda sampai pada kesimpulan yang sama dengan saya pada paragraf terakhir).
Doc Brown
Juga perhatikan arsitektur seluruh proyek, untuk menyesuaikan satu format dengan yang lain. Dapatkah Anda membayangkan situasi di mana seseorang mungkin menggunakan hanya satu bagian dari itu di proyek lain? EG Mungkin validator data baru hadir di pasaran, dan hanya berfungsi dengan SQL server. Jadi sekarang Anda hanya ingin membaca XML kustom dan memasukkannya ke dalam SQL server, melewatkan langkah-langkah selanjutnya.
Andyz Smith
Untuk memfasilitasi ini, tidak hanya potongan-potongan memiliki kontrak internal yang mereka patuhi, harus ada seperangkat kontrak yang menentukan interaksi antara potongan-potongan .
Andyz Smith
@AndyzSmith - Saya memiliki masalah yang sama dalam kode saya. Saya mengerti semua tentang kode Anda kecuali pola Adaptor. Ketika Anda mengatakan seluruh proyek adalah contoh dari pola Adaptor dapatkah Anda menggambarkannya?
gansub
9

Yang jelas adalah menerapkan pola Strategi . Memiliki kelas dasar generik ReadStrategydan untuk setiap format input seperti subkelas XmlReadStrategy, CSVReadStrategydll. Ini akan memungkinkan Anda untuk mengubah pemrosesan impor secara independen dari pemrosesan verifikasi dan pemrosesan keluaran.

Bergantung pada perinciannya, dimungkinkan juga untuk menjaga sebagian besar impor generik dan hanya menukar bagian dari pemrosesan input (misalnya, membaca satu catatan). Ini dapat mengarahkan Anda ke pola Metode Templat .

Doc Brown
sumber
Apakah ini berarti bahwa ketika menggunakan pola strategi, saya harus membuat metode terpisah untuk mengubah objek (pelanggan, alamat) dari sumber ke tujuan. Yang ingin saya lakukan adalah membaca, mengonversi, dan memvalidasi setiap objek dan memasukkannya ke dalam daftar sehingga daftar tersebut nantinya dapat disimpan ke database.
jao
@jao: baik, jika Anda membaca jawaban saya lagi, Anda melihat bahwa saran saya adalah membuat "ReadStrategy", bukan "ConvertStrategy". Jadi Anda hanya perlu menulis metode yang berbeda untuk membaca objek (atau bagian tambahan apa pun dari proses Anda adalah individual untuk format file tertentu).
Doc Brown
7

Pola yang sesuai untuk utilitas impor yang mungkin perlu Anda perluas di masa depan adalah dengan menggunakan MEF - Anda dapat menjaga agar penggunaan memori tetap rendah dengan memuat konverter yang Anda perlukan dengan cepat dari daftar malas, buat impor MEF yang dihiasi dengan atribut. yang membantu memilih konverter yang tepat untuk impor yang Anda coba lakukan dan menyediakan cara mudah untuk memisahkan kelas impor yang berbeda.

Setiap bagian MEF dapat dibangun untuk memenuhi antarmuka pengimporan dengan beberapa metode standar yang mengubah satu baris file impor ke data output Anda atau mengganti kelas dasar dengan fungsionalitas dasar.

MEF adalah kerangka kerja untuk membuat arsitektur plug-in - bagaimana pandangan dan Visual Studio dibangun, semua ekstensi yang indah di VS adalah bagian-bagian MEF.

Untuk membangun aplikasi MEF (Managed Extensability Framework), mulailah dengan menyertakan referensi System.ComponentModel.Composition

Tentukan antarmuka untuk menentukan apa yang akan dilakukan konverter

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

Ini dapat digunakan untuk semua jenis file yang ingin Anda impor.

Tambahkan atribut ke kelas baru yang menentukan kelas apa yang akan "Ekspor"

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

Ini akan menentukan kelas yang akan mengimpor file CSV (dari format tertentu: Format1) dan memiliki atribut khusus yang menetapkan MEF Export Attribute Metadata. Anda akan mengulangi ini untuk setiap format atau jenis file yang ingin Anda impor. Anda dapat mengatur atribut khusus dengan kelas seperti:

[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; }
}

Untuk benar-benar menggunakan pengonversi MEF Anda perlu mengimpor bagian MEF yang Anda buat ketika kode konversi dijalankan:

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

catalog mengumpulkan bagian-bagian dari folder, defaultnya adalah lokasi aplikasi.

converters adalah daftar malas bagian-bagian MEF yang diimpor

Kemudian ketika Anda tahu jenis file yang ingin Anda konversi ( importFileTypedan importType) dapatkan konverter dari daftar bagian yang diimporconverters

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);
....
}

Panggilan ke converter.ImportDataakan menggunakan kode di kelas yang diimpor.

Mungkin tampak seperti banyak kode dan butuh beberapa saat untuk memahami apa yang terjadi tetapi sangat fleksibel ketika harus menambahkan jenis konverter baru dan bahkan dapat memungkinkan Anda untuk menambahkan yang baru saat runtime.

Mat
sumber
Saya belum pernah mendengar MEF sebelumnya. Apa itu?
jao
2
@jao lihat tautan untuk penjelasan lengkap. Menambahkan beberapa contoh barang MEF ke jawaban saya.
Matt
1
Ini adalah cara terbaik untuk memulai MEF. +1
paqogomez
MEF adalah teknologi, bukan pola desain. Tidak -1dari saya karena ide yang mendasarinya masih masuk akal dan bergantung pada pola strategi yang diatur oleh IImportConverterantarmuka.
GETah
0

Apa pola desain yang tepat untuk mengatasi masalah ini?

C # idiom melibatkan penggunaan kerangka kerja serialisasi bawaan untuk melakukan ini. Anda membubuhi keterangan objek dengan metadata, dan kemudian instantiate berbagai serializer yang menggunakan anotasi tersebut untuk merobek data untuk dimasukkan ke dalam formulir yang tepat, atau sebaliknya.

Bentuk Xml, JSON, dan biner adalah yang paling umum, tetapi saya tidak akan terkejut jika yang lain sudah ada dalam bentuk kemasan yang bagus untuk Anda konsumsi.

Telastyn
sumber
Nah, ini berfungsi dengan baik jika Anda bebas menggunakan format file Anda sendiri, tetapi saya kira pendekatan ini akan gagal untuk format yang kompleks dan sudah ditentukan sebelumnya seperti XSLX, yang berarti file MS Excel dalam format XML terkompresi.
Doc Brown
Saya dapat memetakan satu baris file Excel ke suatu objek, tetapi saya perlu menyalin dan mengadaptasi metode itu ke pembaca XML dan CSV. Dan saya ingin menjaga kode sebersih mungkin ...
jao
@docBrown - bagaimana? Secara konseptual, mengubah objek menjadi serangkaian sel di Excel tidak benar-benar berbeda dengan mengubahnya menjadi dokumen xml.
Telastyn
@ Telastyn: Anda mengatakan Anda dapat menggunakan kerangka kerja serialisasi bawaan dari kerangka .NET untuk membaca format XLSX? Jika itu benar, perpustakaan seperti Open XML SDK atau NPOI sudah usang.
Doc Brown
@docbrown: permintaan maaf saya, Anda benar - Saya selalu lupa bahwa tidak ada kelas dasar serializer umum karena itu adalah salah satu hal pertama yang dilakukan di basis kode apa pun yang saya gunakan.
Telastyn