さまざまなソースタイプおよびさまざまな宛先タイプへのデータインポートのデザインパターン


14

次を処理できるインポートスクリプト(C#)を設計および構築する必要があります。

  • さまざまなソース(XML、XSLX、CSV)からデータを読み取る
  • データを検証する
  • データをさまざまなオブジェクトタイプ(顧客、住所)に書き込む

データは多数のソースから取得されますが、ソースには常に1つのインポート形式(csv、xml、xslxのいずれか)があります。インポート形式はソースごとに異なる場合があります。将来、新しいインポート形式が追加される可能性があります。宛先オブジェクトの種類は常に同じです(顧客、アドレスなど)。

私はジェネリックを使用することを考えていて、ファクトリーパターンについて何かを読みましたが、私はこの分野でかなり大きな初心者なので、アドバイスは大歓迎です。

この問題を解決するための適切な設計パターンは何ですか?


複雑にしないでおく。
-NoChance

回答:


11

あなたは派手なコンセプトで船に乗り過ぎていました。ジェネリック-ケースが表示された場合はそれらを使用しますが、それ以外は心配しないでください。工場出荷時のパターン-これにはまだ柔軟性がありすぎて(さらに混乱が生じています)。

複雑にしないでおく。基本的なプラクティスを使用します。

  1. XMLの読み取りと、CSVの読み取りを行うことの間の一般的なことを想像してみてください。次のレコード、次の行のようなもの。新しい形式が追加される可能性があるため、決定される形式と既知の形式との共通性を想像してみてください。この共通性を使用して、すべての形式が遵守する必要がある「インターフェース」または契約を定義します。それらは共通の基盤に固執していますが、すべて特定の内部ルールを持っている可能性があります。

  2. データを検証するには、新しいまたは異なる検証コードブロックを簡単にプラグインする方法を提供してください。繰り返しになりますが、特定の種類のデータ構築を担当する各バリデーターが契約を遵守するインターフェースを定義してみてください。

  3. データ構造を作成する場合、提案された出力オブジェクトを何よりも設計する人に制約される可能性があります。データオブジェクトの次のステップが何であるかを理解してみてください。最終的な使用方法を知ることで最適化を行うことができますか。たとえば、オブジェクトがインタラクティブアプリケーションで使用されることがわかっている場合、オブジェクトの「合計」またはカウントまたはその他の種類の派生情報を提供することで、そのアプリの開発者を支援できます。

これらのほとんどは、テンプレートパターンまたは戦略パターンです。プロジェクト全体がアダプタパターンになります。


+1、特に最初の段落について(そして、最後の段落で私と同じ結論に達したことを見るのは素晴らしいことです)。
Doc Brown

また、1つの形式を別の形式に適応させるために、プロジェクト全体のアーキテクチャを念頭に置いてください。誰かが別のプロジェクトでその一部のみを使用するような状況を想像できますか?EGおそらく新しいデータバリデータが市場に出回っており、それはSQLサーバーでのみ機能します。したがって、カスタムXMLを読み取り、残りの手順をスキップしてSQLサーバーに配置するだけです。
アンディズスミス

これを容易にするために、ピースが従う内部契約を持っているだけでなく、ピース間の相互作用を定義する一連の契約があるべきです。
アンディズスミス

@AndyzSmith-コードに同じ問題があります。アダプタパターン以外のコードについてすべて理解しました。プロジェクト全体がアダプタパターンの例だと言ったとき、それを説明できますか?
ガンサブ

9

明らかなことは、戦略パターンを適用することです。汎用の基本クラスをReadStrategy持ち、入力形式ごとXmlReadStrategyCSVReadStrategyなどのサブクラスを作成します。これにより、検証処理および出力処理とは別にインポート処理を変更できます。

詳細によっては、インポートジェネリックのほとんどの部分を保持し、入力処理の一部のみを交換することもできます(たとえば、1つのレコードの読み取り)。これにより、テンプレートメソッドパターンが表示される場合があります。


戦略パターンを使用する場合、オブジェクト(顧客、住所)をソースから宛先に変換するための個別のメソッドを作成する必要があるということですか?私がやりたいのは、各オブジェクトを読み取り、変換し、検証し、リストに入れて、後でリストをデータベースに保存できるようにすることです。
jao

@jao:私の答えをもう一度読んでみると、私の提案は「ConvertStrategy」ではなく「ReadStrategy」を作成することでした。そのためオブジェクトを読み取るためのさまざまなメソッドを作成するだけで済みます(または、プロセスの追加部分が特定のファイル形式に対して個別のものである場合)。
Doc Brown

7

将来拡張する必要があるかもしれないインポートユーティリティの適切なパターンは、MEFを使用することです。必要なコンバータを遅延リストからオンザフライでロードし、属性で装飾されたMEFインポートを作成することにより、メモリ使用量を低く抑えることができます実行しようとしているインポートに適したコンバータを選択するのに役立ち、インポートするさまざまなクラスを簡単に分離する方法を提供します。

各MEFパーツは、インポートファイルの行を出力データに変換したり、基本機能で基本クラスをオーバーライドしたりするいくつかの標準メソッドを使用して、インポートインターフェイスを満たすように構築できます。

MEFはプラグインアーキテクチャを作成するためのフレームワークです-その外観とVisual Studioの構築方法、VSのこれらの素敵な拡張機能はすべてMEFパーツです。

MEF(Managed 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
パコゴメス14年

MEFは技術であり、デザインパターンではありません。-1根底にあるアイデアはまだ理にかなっており、IImportConverterインターフェイスによって支配される戦略パターンに依存しているので、私からはだめです。
ゲタ

0

この問題を解決するための適切な設計パターンは何ですか?

C#のイディオムでは、組み込みのシリアル化フレームワークを使用してこれを行います。オブジェクトにメタデータで注釈を付け、それらの注釈を使用してデータを取り出して適切なフォームに入れたり、またはその逆に使用するさまざまなシリアライザーをインスタンス化します。

Xml、JSON、およびバイナリ形式が最も一般的ですが、他のユーザーが使用できる素敵なパッケージ形式で既に存在していても驚かないでしょう。


独自のファイル形式を自由に使用できる場合、これはうまく機能しますが、XSLXなどの複雑な定義済み形式、つまり圧縮XML形式のMS Excelファイルでは、この方法は失敗すると思います。
Doc Brown

Excelファイルの行をオブジェクトにマッピングできますが、そのメソッドをコピーしてXMLリーダーとCSVリーダーに適合させる必要があります。そして、私は...できるだけクリーンとしてコードを維持したいのですが
ジャオ

@docBrown-ハウソ?概念的には、Excelでオブジェクトを一連のセルに変換することは、実際にXMLドキュメントに変換することと何の違いもありません。
テラスティン

@Telastyn:.NETフレームワーク組み込みシリアル化フレームワークを使用し XLSX形式を読み取ることができると言いますか?もしそうなら、Open XML SDKやNPOIのようなライブラリは廃止されました。
Doc Brown

@docbrown:私の謝罪、あなたは正しいです-私はそれがで任意のコードベースのI作業で行われます最初のものの一つだから共通シリアライザ基本クラスはありませんことを忘れておく。
Telastyn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.