問題ドメイン:
金融商品にはさまざまなタイプがあり、さまざまなシナリオでそれらをシミュレートしようとしています。製品タイプごとに異なる入力データが必要です。入力データがデータベーステーブルで編成されている場合、特定の製品の入力データには独自の列の合計数があり、列は他のタイプと比較してビジネス上の意味が異なる場合があります。さらに、製品タイプごとに、そのタイプの実際の製品が多数(500,000など)存在する可能性があり、各製品はテーブル内のデータレコードになります。
たとえば、製品タイプAの入力データには、フィールド「a_1」、「a_2」、「a_3」...「a_20」が含まれる場合があります。製品Bの入力データには、「b_1」、「b_2」、「b_3」...「b_25」が含まれる場合があります。すべての製品タイプの入力データ構造を事前に明確に定義して使い尽くすことは不可能です。ユーザーは、新しい入力データ要件を持つ新しい製品タイプを導入する場合があります。
入力データはデータ要素の数とそのビジネス上の意味で異なりますが、製品タイプ全体のデータ要素はいくつかのグループに抽象化でき、c#を使用して実装された一般的な計算エンジンを使用して、各グループを同じように処理できます。
ユーザーは、製品タイプの入力データファイルを準備します。次に、ユーザーはGUIを個別に使用して、入力ファイルに含まれるデータのグループを計算エンジンに通知します。計算エンジンは、GUIからの情報を使用して、入力ファイルからのデータを解釈し、計算を実行します。
動的で変化する入力データを計算エンジンに渡そうとしています。
試みられた解決策:
試行1:
すべての製品タイプに対して、1つのサイズですべてに対応するデータ構造を用意します。これには、最も複雑なデータ型のニーズを満たすために、多数のデータフィールドが必要になります。さらに、データレコードを表すためにオブジェクトを使用することも試みています。このアプローチでは、オブジェクトには未使用のデータフィールドも含まれます。製品タイプの多数のデータレコード(したがってオブジェクト)を考慮すると、このアプローチは困難な場合があります。
このアプローチでは、「a_1」や「a_2」ではなく、「field_1」や「field_2」などの一般的なフィールド名も必要になります。一般的なフィールド名は混乱を招く可能性があり、実際のユーザーフィールド名への追加のマッピングが必要になる場合があります。
試み2:
たぶん、私はone-size-fits-allではなく、「a-few-sizes-fit-all」のように、さまざまな一般的なデータ構造を持つことができると考えていました。たぶん、最大20のデータ要素のニーズを満たすためのデータ構造1、最大30のデータ要素のニーズを満たすためのデータ構造2などがあります。これは、データテーブルをクリーンにし、オブジェクトのサイズを減らすのに役立ちます。この場合、計算エンジンはさまざまなデータクラスを処理する必要があります。クラスはコンパイル時にまだわかっています。
試行3:
さまざまな製品タイプのクラスを動的に生成し、計算エンジンが実行時に生成されたクラスを処理するようにします。これにはパフォーマンスの問題があるかもしれません。また、不明なデータクラスを処理するよう要求することで、計算エンジンをより複雑にします。
質問:
入力データの構造とデータレコードを表すためのオブジェクトの使用についての私の考え(解決策を試みた場合)は合理的でしょうか。より良い解決策はありますか?ありがとう!
それは一般に要件に依存しますが、多くの場合、それはあなたが自由に使える時間に依存します。なぜなら、多くの矛盾する要件が発生した場合、そこから実際に実装とビルドを開始し、アーキテクチャを改善しなければならない場合があるためです。 go(コードの破棄を含む場合があります)。
まず第一に、多くのテーブルとテーブルごとのレコードのロードを持つ複数のデータベースは、ほとんどの優れたデータベース実装にとって特別なものではなく、とにかく優れたものはその点ですでに「カバー」されているので、これはあなたが心配すべきものではありませんあらかじめ。
次に、(通常は)アーキテクチャを設計してはならず、実装に基づいてアーキテクチャについて推論する必要があります。抽象化に基づいて設計および推論する必要があります。ドメインの実際のオブジェクトではなく、クラスとフィールドについて(そしてその結果として考えて)話している。 「20データ要素」や「30データ要素」などの非常に具体的な数値について言及しているようですが、それらの「例」として、特定の20〜30データ要素は「ダウン」していますか。 20から30のデータ要素をメモし(以下も同様)、ユースケースに共通するものを確認します。金融商品にはおそらく価格があり、おそらく他のいくつかの共通の特性があります。
ただし、ドメインの表現は潜在的なユースケースからほぼ完全に切り離されている場合がありますが、実装する必要があるのはユースケースであることを覚えておいてください。多くの場合、それは関係を概念化し、特定の方法でそれを検討している真の理由を(自分自身に)明らかにするのに役立ちます。次に、ドメインロジックとユースケースの間を往復することにより、独自の推論を微調整できます。
たとえば、金融商品は、ある意味では、一般的であるはずの「金融」特性(たとえば、価格)、次に名前/説明、そして場合によっては1つ以上の描写/画像の面で興味深いので、オブジェクトのグループを管理し、購入やその他のさまざまなアクティビティを容易にします。これらすべてが、データベース上で単純または複雑な操作を単に表すという共通の基盤を共有します。
しかし、説明したユースケースを見てください。行と列、それらの多くは、データベースのコンテンツの仮想化として機能します。次に、オブジェクトには多くのプロパティがあるように見えます。私はあなたの「計算エンジン」が何であれ、オッズが極めて低いという不人気な声明を出しますallこれらのプロパティはそのエンジンに関連しています。なんらかの理由で、それらが必要であり、それらがすべて必要であり、それらも共通の基盤ではない場合は、次の簡単な方法で計算エンジンのリファクタリングを開始する必要があります。
現在想像しているように、allオブジェクトには特定の型があり、動的型推論または型チェックを使用して、計算エンジンで処理を実行できます。これはtoo悪いことではありません。フィールドで遊ぶよりも、強い型でオブジェクトを分離し、計算エンジンでいくつかの型チェックを使用するのに役立ちますオブジェクトが特定のタイプであるかどうかを確認する名前など.
しかし、私が提案する方法は、何を再考することですこれは、この計算エンジンが行うことです。たとえば、プロパティに基づいて価格を計算し、オブジェクトの特性が大きく異なる場合(そしてもちろん、複数の非常に異なるプロパティがある場合)、オブジェクトに「血液」を入れるだけです。クラス(貧血ドメインモデルを調べて、最終的にはあまり役に立たない方法を調べてみてください)と機能を提供します。彼らが自分で価格を計算できるようにして、メソッドGetPrice()
を持つIFinancial
などの共通インターフェイスを実装します。このようにして、計算はオブジェクト内で行われ、ユースケースコードが編成されている場所でタイプチェックを行う必要はありません。オブジェクトを尋ねるだけです。
ああ、残りの(非共通?)プロパティで埋める必要があるこれらの行と列について、まあ、それらに「財務的」なものがなければ、なぜこれらのプロパティが必要なのかわかりません。計算エンジン。参照用に存在する場合は、キーと値のペアとしてモデル化できます。 Dictionary<string, string>
で十分です。
不完全なドメインをモデル化しようとした場合、または不完全にドメインをモデル化しようとした場合に、いくつかのサイズに当てはまるソリューションが発生します。もちろん、私はその専門家ではありませんが、それらは避けたほうがよいです。さらに、現実の世界は複雑すぎて絶対に対処できません。
開発者はコードを見たいので:
public class FinancialObject : IFinancial
{
//Common properties of IFinancial
Currency GetPrice(); //Currency is some proper abstraction.
//Maps property code-string (key) to property value.
Dictionary<string, string> AdditionalProperties { get; }
//Maps property code-string (key) to property user-friendly description/name.
Dictionary<string, string> AdditionalPropertyDescriptiveNames { get; }
}