私は、DI/IoC、NHibernate に頭を悩ませ、開発中のアプリケーションでそれらをうまく連携させようとしています。私はNHibernateとDI/IoCの両方にまったく慣れていないので、私がやっていることは賢明な方法であるかどうかはよくわかりません。これはシナリオです:
このアプリケーションは、特定の金融取引の特定の値 (証拠金と呼ばれる) を計算する機能をユーザーに提供します。各トランザクションのマージン値の計算は、抽象的な MarginCalculator クラスの具体的な実装によって実行され、使用される具体的な実装は、特定のトランザクション (製品オブジェクトの特定のフィールドによって与えられる) の製品のタイプによって異なります。具体的な電卓クラスには、製品クラスのプロパティを介してアクセスします。すなわち
public class Transaction
{
private double _margin;
private Product _product;
private Client _client;
public double Margin { get; }
public Product Product { get; }
public Client Client { get; }
public Transaction(Product p, Client c)
{
_product = p;
_client = c;
}
public void CalculateMargin()
{
_margin = _product.MarginCalculator.CalculateMargin();
}
}
public class Product
{
private string _id;
private string _productType;
... Other fields
public string Id { get; }
public string ProductType { get; }
public MarginCalculator MarginCalculator
{
get { return MarginCalculatorAssembler.Instance.CreateMarginCalculatorFor(this.ProductType); }
}
}
public class MarginCalculatorAssembler
{
public static readonly MarginCalculatorAssembler Instance = new MarginCalculatorAssembler();
private MarginCalculatorAssembler ()
{
}
public MarginCalculator CreateMarginCalculatorFor(string productType)
{
switch (productType)
{
case "A":
return new ConcreteMarginCalculatorA();
case "B":
return new ConcreteMarginCalculatorB();
default:
throw new ArgumentException();
}
}
}
public abstract class MarginCalculator
{
public abstract double CalculateMargin();
}
public class ConcreteMarginCalculatorA : MarginCalculator
{
public override double CalculateMargin
{
// Perform actual calculation
}
}
public class ConcreteMarginCalculatorB : MarginCalculator
{
public override double CalculateMargin
{
// Perform actual calculation
}
}
ユーザーがドロップダウンから特定のクライアントと製品を選択すると、対応する clientId と productId がリポジトリに渡され、NHibernate を使用してトランザクション オブジェクトに注入される前に製品とクライアント オブジェクトにデータが入力されます。私の現在のセットアップでは、トランザクションはコンストラクター依存性注入を介して製品とクライアントの依存性を受け取ります (まだ IoC コンテナーは使用されていません)。
public class ProductRepository : IRepository<Product>
{
public Product GetById(string id)
{
using (ISession session = NHibernateHelper.OpenSession())
return session.Get<Product>(id);
}
}
/* Similar repository for Clients */
IRepository<Client> clientRepository = new ClientRepository();
IRepository<Product> productRepository = new ProductRepository();
Client c = clientRepository.GetById(clientId);
Product p = productRepository.GetById(productId);
Transaction t = new Transaction(p, c);
以下は、私がアイデアを得ることを望んでいるものです。
A. Product ドメイン オブジェクトを介して MarginCalculator (本質的にはサービス) にアクセスすることは問題ないと考えられますか、それとも、ここで提案されているように ( http://stackoverflow.com/questions/340461/dependency-injection-with-nhibernate -objects ) ドメイン オブジェクトからサービスの依存関係を削除し、代わりに抽象的な MarginCalculator を依存関係として受け取る新しい TransactionProcessor クラスを作成するようにコードを再構築する必要があります (ここで説明されている行に沿って ( http://www.lostechies.com ) /blogs/jimmy_bogard/archive/2008/03/31/ptom-the-dependency-inversion-principle.aspx ) すなわち
public class TransactionProcessor
{
private readonly MarginCalculator _marginCalculator;
public TransactionProcessor(MarginCalculator marginCalculator)
{
_marginCalculator = marginCalculator;
}
public double CalculateMargin(Transaction t)
{
return _marginCalculator.CalculateMargin(Transaction t);
}
}
public abstract class MarginCalculator
{
public abstract double CalculateMargin(Transaction t);
}
B. IoC コンテナーを使用して、NHibernate に入力/生成された製品とクライアントの依存関係が注入されたトランザクション オブジェクトを取得することは可能ですか? つまり、両方ともユーザーが提供する productId と clientId を指定すると、次のようなものを持つことができます。
// pseudocode
Transaction t = IoC.Resolve<Transaction>(productId, clientId);
コンテナーがトランザクション オブジェクトの製品とクライアントの依存関係を解決するように、NHibernate を使用して、productId と clientId に基づいて製品とクライアントを入力し、入力された製品とクライアントをトランザクションに挿入しますか?
C.典型的な DI シナリオでは、クラス A がインターフェイス B に依存している場合、次のことが行われる可能性があります。
IInterfaceB b = new ClassB();
A a = new A(b);
interface IInterfaceB
{
}
class B : IInterfaceB
{
}
public class A
{
private IIntefaceB _b;
public A(IInterfaceB b)
{
_b = b;
}
}
ただし、これは実質的に DI のすべての例が示されている方法であり、IInterfaceB (この場合はクラス B) の実装者が設計時にわかっていることを前提としています。実装者が実行時に決定されるような方法で DI を使用する方法はありますか?
どうもありがとう
マシュー