Шаблон дизайну для імпорту даних різних типів джерел та різних типів призначення


14

Мені потрібно розробити та створити сценарій імпорту (в C #), який може обробляти наступне:

  • читати дані з різних джерел (XML, XSLX, CSV)
  • перевірити дані
  • записувати дані в різні типи об'єктів (клієнт, адреса)

Дані надходять з ряду джерел, але джерело завжди матиме один формат імпорту (або csv, xml, xslx). Формати імпорту можуть відрізнятися від джерела до джерела. В майбутньому можуть бути додані нові формати імпорту. Типи цільових об'єктів завжди однакові (клієнт, адреси та деякі інші).

Я думав про використання дженериків і читав щось про заводський зразок, але я досить великий ноб у цій галузі, тому будь-яка порада є більш ніж вітаю.

Яка відповідна модель дизайну для вирішення цієї проблеми?


Не ускладнювати.
NoChance

Відповіді:


11

Ви перебираєтесь за кордон з фантазійними концепціями, було занадто рано. Generics - коли ви бачите випадок, використовуйте їх, але в іншому випадку не хвилюйтеся. Заводський зразок - для цього занадто велика гнучкість (і додана плутанина).

Не ускладнювати. Використовуйте фундаментальні практики.

  1. Спробуйте уявити спільні речі між читанням для XML, читанням для CSV будь-якого. Такі речі, як наступний запис, наступний рядок. Оскільки нові формати можуть бути додані, спробуйте уявити спільність, яку має визначати формат із відомими. Використовуйте цю спільність і визначте "інтерфейс" або контракт, якого повинні дотримуватися всі формати. Хоча вони дотримуються спільної позиції, всі вони можуть мати свої специфічні внутрішні правила.

  2. Для перевірки даних спробуйте запропонувати спосіб легко підключити нові або різні блоки кодів валідатора. Тому знову спробуйте визначити інтерфейс, де кожен валідатор, відповідальний за певний вид побудови даних, дотримується договору.

  3. Для створення конструкцій даних ви, мабуть, буде обмежений тим, хто розробляє запропоновані вихідні об'єкти більше ніж усе. Спробуйте розібратися, що таке наступний крок для об’єктів даних, чи є оптимізації, які ви можете зробити, знаючи остаточне використання. Наприклад, якщо ви знаєте, що об’єкти будуть використовуватися в інтерактивному додатку, ви можете допомогти розробнику цього додатка, надавши "підсумки" або підрахунки об'єктів або інших видів отриманої інформації.

Я б сказав, що більшість із них є шаблонами шаблонів або стратегіями. Весь проект буде схемою адаптера.


+1, особливо для першого абзацу (і приємно бачити, що ви дійшли такого ж висновку, як і я в останньому абзаці).
Док Браун

Також пам’ятайте про архітектуру всього проекту, щоб адаптувати один формат до іншого. Чи можете ви уявити будь-яку ситуацію, коли хтось може використовувати лише одну частину цього в іншому проекті? EG Можливо, на ринку з'явиться новий валідатор даних, який працює лише з SQL-сервером. Отже, тепер ви просто хочете прочитати користувальницький XML і помістити в SQL сервер, пропустивши решту кроків.
Andyz Smith

Щоб полегшити це, не тільки, якщо у творів є внутрішні контракти, яких вони дотримуються, повинен бути набір контрактів, що визначають взаємодію між частинами .
Andyz Smith

@AndyzSmith - у мене є однакова проблема в коді. Я зрозумів все про ваш код, за винятком схеми адаптера. Коли ви сказали, що весь проект є прикладом моделі адаптера, чи можете ви проілюструвати це?
gansub

9

Очевидним є застосування стратегії . Є загальний базовий клас ReadStrategyі для кожного формату вхідного підклас , як XmlReadStrategy, і CSVReadStrategyт.д. Це дозволить вам змінити обробку імпорту незалежно від обробки verfication і обробки продукції.

Залежно від деталей, можливо також зберегти більшість частин загального імпорту та обмінятись лише частинами вхідної обробки (наприклад, зчитування одного запису). Це може призвести до шаблону методу шаблону .


Чи означає це, що при використанні шаблону стратегії я повинен створити окремі методи перетворення об’єктів (клієнта, адреси) від джерела до місця призначення. Що я хотів би зробити, це прочитати, перетворити та перевірити кожен об’єкт та помістити його у список, щоб згодом список був збережений у базі даних.
jao

@jao: ну якщо ви ще раз прочитаєте мою відповідь, ви побачите, що моя пропозиція полягала в тому, щоб створити "ReadStrategy", а не "ConvertStrategy". Тому вам потрібно лише писати різні методи для читання об'єктів (або будь-яка додаткова частина вашого процесу індивідуальна для конкретного формату файлу).
Док Браун

7

Підходящою схемою для утиліти, що імпортує, яку, можливо, вам потрібно буде розширити в майбутньому, було б використовувати MEF - ви можете зберегти низьке використання пам’яті, завантажуючи потрібний перетворювач на льоту з ледачого списку, створювати імпорт MEF, прикрашений атрибутами які допомагають вибрати потрібний перетворювач для імпорту, який ви намагаєтеся виконати, і забезпечує простий спосіб відокремити різні класи імпорту.

Кожна частина MEF може бути побудована так, щоб задовольнити інтерфейс імпорту за допомогою деяких стандартних методів, які перетворюють рядок файлу імпорту у вихідні дані або замінюють базовий клас з базовою функціональністю.

MEF - це основа для створення архітектури плагінів - як будуються перспективи та Visual Studio, всі ці чудові розширення в VS є частиною MEF.

Щоб створити програму MEF (Managed Framework Extensability Framework), почніть з включення посилання на System.ComponentModel.Composition

Визначте інтерфейси, щоб визначити, що буде робити перетворювач

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

Це можна використовувати для всіх типів файлів, які ви хочете імпортувати.

Додайте атрибути до нового класу, які визначають, який клас буде "Експортувати"

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

Це визначило б клас, який імпортуватиме файли CSV (певного формату: Format1) та має власні атрибути, що встановлюють метадані експортних атрибутів MEF. Ви повторите це для кожного формату або типу файлу, який потрібно імпортувати. Ви можете встановити власні атрибути з таким класом, як:

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

Для того, щоб фактично використовувати перетворювачі MEF, вам потрібно імпортувати деталі MEF, які ви створюєте під час запуску коду перетворення:

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

catalog збирає частини з папки, за замовчуванням - місце розташування програми.

converters - лінивий список імпортованих деталей MEF

Тоді, коли ви знаєте, який тип файлу ви хочете перетворити ( importFileTypeі importType), отримайте конвертер зі списку імпортованих частин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);
....
}

Заклик до converter.ImportData буде використовувати код у імпортованому класі.

Можливо, це виглядає як багато коду, і це може зайняти деякий час, щоб обернутися тим, що відбувається, але його надзвичайно гнучко, якщо мова йде про додавання нових типів перетворювачів і навіть може дозволити вам додавати нові під час виконання.


Я не чув про MEF раніше. Що це?
jao

2
@jao перевірити посилання для повного пояснення. До моєї відповіді додали деякі приклади матеріалів MEF.
Метт

1
Це відмінний спосіб почати роботу в MEF. +1
paqogomez

MEF - це технологія, а не модель дизайну. Ні -1від мене, оскільки основна ідея все ще має сенс і спирається на шаблон стратегії, керований IImportConverterінтерфейсом.
GETah

0

Яка відповідна модель дизайну для вирішення цієї проблеми?

C # ідіоми передбачають використання вбудованої в серіалізаційну рамку для цього. Ви коментуєте об’єкти метаданими, а потім створюєте інстанціювання різних серіалізаторів, які використовують ці анотації для видобутку даних для правильної форми або навпаки.

Xml, JSON та бінарні форми є найпоширенішими, але я не здивуюсь, якщо інші вже існують у приємній упакованій формі для споживання.


Ну, це добре працює, якщо ви вільні у використанні власного файлового формату, але, мабуть, такий підхід не вдасться для складних, заздалегідь визначених форматів, таких як XSLX, що означає файли MS Excel у стисненому форматі XML.
Док Браун

Я можу зіставити рядок файлу Excel до об’єкта, але мені потрібно скопіювати та адаптувати цей метод до читачів XML та CSV. І я хотів би, щоб тримати код як чистий , наскільки це можливо ...
Jao

@docBrown - як? Концептуально перетворення об'єкта в ряд комірок в Excel насправді не відрізняється від перетворення його в XML-документ.
Теластин

@Telastyn: Ви кажете, що ви можете використовувати вбудовану рамку серіалізації рамки .NET для читання формату XLSX? Якби це було правдою, бібліотеки на зразок Open XML SDK або NPOI були застарілими.
Док Браун

@docbrown: мої вибачення, ви праві - я продовжую забувати, що немає загального базового класу серіалізаторів, оскільки це одне з перших речей, що робиться в будь-якій
кодовій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.