- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在努力了解 DI/IoC、NHibernate,并让它们在我正在开发的应用程序中很好地协同工作。我对 NHibernate 和 DI/IoC 都很陌生,所以不太确定我正在做的事情是否是明智的做法。这是场景:
该应用程序为用户提供了为特定金融交易计算特定值(称为 margin )的能力。每笔交易的 margin 值的计算是通过抽象 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 填充产品和客户端对象,然后再将它们注入(inject)交易对象。在我当前的设置中,事务通过构造函数依赖注入(inject)(尚未使用 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 ) 重构代码以便从域对象中删除服务依赖项,而是创建一个新的 TransactionProcessor 类,该类将抽象的 MarginCalculator 作为依赖项(按照此处描述的内容 (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 容器来获取事务对象,其中注入(inject)了 NHibernate 填充/生成的产品和客户端依赖项?即,给定一个由用户提供的 productId 和 clientId,是否有可能是这样的:
// pseudocode
Transaction t = IoC.Resolve<Transaction>(productId, clientId);
这样容器就解析了Transaction对象的Product和Client依赖,利用NHibernate根据productId和clientId填充Product和Client,然后将填充的Product和Client注入(inject)到Transaction中?
C. 在典型的 DI 场景中,如果类 A 依赖于接口(interface) 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?
非常感谢
马修
最佳答案
A) 如果您要通过 Product 域对象访问 MarginCalculator,您不妨去掉中间人,让 DI/IOC 容器为您注入(inject) MarginCalculator。您甚至可以摆脱 MarginCalculatorAssembler,因为大多数 DI/IOC 容器都会为您完成对象构造的大部分样板代码。
B 和 C) 很有可能。事实上,如果你使用 LinFu,你的代码会是这样的:
// No need to change the Transaction classpublic 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(); }}
如果您可以使用 DI/IOC 将产品和客户端实例注入(inject)构造函数,那就太好了——但在我们这样做之前,您需要向容器注册依赖项。以下是使用 LinFu.IOC 的方法:
// Next, you'd have to tell LinFu to automatically register your product class:[Factory(typeof(Product))]public class ProductFactory : IFactory{ object CreateInstance(IServiceRequest request) { // Grab a copy of the IRepository from the container var repository = container.GetService>(); // Get the id (this assumes that your id is an Int32) var id = (int)request.Arguments[0]; // Return the product itself return repository.GetById(id); }}// Do the same thing with the Client class// (Note: I did a simple cut and paste to keep things simple--please forgive the duplication)[Factory(typeof(Client))]public class ClientFactory : IFactory{ object CreateInstance(IServiceRequest request) { // Grab a copy of the IRepository from the container var repository = container.GetService>(); // Get the id (this assumes that your id is an Int32) var id = (int)request.Arguments[0]; // Return the client itself return repository.GetById(id); }}[Factory(typeof(Transaction))]public class TransactionFactory : IFactory{ object CreateInstance(IServiceRequest request) { // Note: Argument checking has been removed for brevity var container = request.Container; var arguments = request.Arguments; var productId = (int)arguments[0]; var clientId = (int)arguments[1]; // Get the product and the client var product = container.GetService(productId); var client = container.GetService(clientId); // Create the transaction itself return new Transaction(product, client); }}// Make this implementation a singleton[Implements(typeof(MarginCalculator), LifecycleType.Singleton)]public class ConcreteMarginCalculatorA : MarginCalculator{ public override double CalculateMargin() { // Perform actual calculation }}
将所有代码编译到一个程序集中后,只需执行以下操作即可将其加载到容器中:
var container = new ServiceContainer();container.LoadFrom(AppDomain.CurrentDomain.BaseDIrectory, "YourAssembly.dll");
...现在是有趣的部分。为了使用给定的产品和客户端 ID 创建您的交易对象,这是您需要对 LinFu.IOC 的容器进行的调用:
int productId = 12345;int clientId = 54321;string serviceName = null;// Not pseudocode :)var transaction = container.GetService(serviceName, productId, clientId);
有趣的是,尽管您可能有很多依赖项,但 LinFu 的 IOC 容器将为您处理 90% 的样板代码,因此您不必自己完成所有这些工作。 最好的部分是上面的所有实现都将在运行时确定/解决。
您几乎可以在程序运行时交换实现,甚至无需重新编译您的应用程序就可以替换实现。您可以在此处找到更多信息:
http://www.codeproject.com/KB/cs/LinFu_IOC.aspx
HTH:)
关于c# - DI/IoC、NHibernate 并帮助它们协同工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/387783/
我想插入 备注 关于要在我的 latex 文档的特定位置进行的修复 也许有一个 列表的“待办事项/修复我” 你怎么处理这个? 似乎一种方法是使用 fixme 包,但我无法使其工作。 有人在用吗? 最佳
错误:无法创建表。我已经创建了一个数据库,并且已经提供了所有特权。但仍然无法登录协作模块。我受够了,但我不想放弃。我已经尝试了所有可能的方法,但都行不通。 Stackoverflow 是我所知道的最好
我是一名优秀的程序员,十分优秀!