2014-03-04 17 views
0

我试图创建一个名为产品业务逻辑类,在这里我传递一个单位的工作(本单位的工作是通过依赖注入创建):当我有多个Unit-Of-Work实现时,我应该如何抽象出我的业务级别类?

var products = new Products(uow); //uow implements IUnitOfWork 

产品有一个名为方法添加

int newID = products.Add("my widget"); 

现在假设我有两个实现了IUnitOfWork,SqlServer的InMemoryMock。类的所有方法的业务逻辑基本上是相同的,但是在某些情况下,内部工作基于持久性而变化,或者在此情况下使用IUnitWork的哪个实现。我们假设这种方法就是其中一种。

为了有不同的实现,我可以使产品成为一个抽象类,然后从中继承,并使方法抽象并强制实现覆盖此方法。

然而,这需要我创造某种ProductFactory,这将返回正确的类:

var products = ProdcutFactory.Get(uow); //return the SqlServer or InMemoryMock version 

这需要我的应用程序引用具有ProductFactory,从而起到一个参考的装配SqlServer和InMemoryMock程序集。根据Mark Seemann的令人难以置信的书,这是一个禁忌。

有没有更好的方法来完成我的抽象尝试? (有没有办法来ping马克塞曼我知道他是活跃在SO?)

编辑:

对于我SqlServer的实施,我需要真正的节约(未提交)我添加的行,以获得新行的ID将其返回给消费者(MVC控制器)。所以我的SqlServer实现产品将有这个额外的电话。我的MVC控制器不应该关心它使用哪种类型的产品

我正试图找到一种方法来创建产品类,该类匹配传递到控制器中的IUnitOfWork的类型。 我担心的是我的MVC项目不应该引用我的InMemoryMock实现

是否使用了Mark的书(页面?)中引用的AbstractFactory我开始感觉到DI容器会在这个工厂中通过。

编辑#2: 比方说,我的添加方法插入使用存储库一行到我的SQL数据库,并为相关表中的ID列是自动增量列。然后我需要该ID用于后续操作。我可以得到价值的唯一方法是调用保存方法上IUnitOfWork(当然,我可以调用commit,但我不想犯,只是还没有)

uow.ProductRepo.Insert(new UserModel(){..... 
uow.Save(); 
var uid = uow.ProductRepo.Get(u => u.someuniquecode == someUniqueCode)....... (etc) 

现在,如果我在做模拟版本,我不需要在UOW上调用Save方法,但我宁愿在插入过程中提供ID。

var uid = uow.ProductRepo.Get(some lambda to get the largest ID) + 1 
uow.ProductRepo.Insert(new UserModel(ID = uid, ....... 

所以我基本上有两个版本添加,各做类似的事情,但在我的消费者在没有任何兴趣不同的方式。


我通过依赖注入来创建我的UOW(包含回购)。我创建了一些采用UOW的“职员”类,他们执行业务功能。无论我的UOW类型如何(这实际上都基于存储库类型),业务逻辑都是相同的,但是存储库的工作方式略有不同,特别是自动增量索引功能。

我所做的就是创建一个名为产品一个抽象的商业类,它实现IProductClerk(它本身实现IDisposable),并把我的业务逻辑的肉有。我有两个单独的库(business.mock和business.sqlserver),在这里我实现了这个抽象类,并且覆盖了所有不能使用“标准”逻辑的方法。我的消费者得到了IProductClerk的实例,所以两个实现看起来都是一样的(希望这能满足LSP)。

我也有一个IProductClerkFactory接口,并在我的business.mock和business.sqlserver类,我创建ProductClerkFactory:IProductClerkFactory其返回其实施IProductClerk的。

在我的控制器,需要IProductClerk,我加IProductClerkFactory productClerkFactory的构造函数,然后在我的作文根I配置IProductClerkFactory应该使用business.sqlserver.clerk.ProuctClerkFactory。

当我的控制器被调用时,我得到了正确类型的IProductClerkFactory(我的用户不关心),从那里我可以生成一个IProductClerk并传入持久性依赖项(工作单元)。

对于我的单元测试,我从模拟库中创建了一个工厂实例,对于集成测试,我使用了sql库。

这是怎么回事?

+0

不知道我是否理解整个问题,但无法定义Abstract Factory('IProductFactory')? –

+0

哈哈。我刚刚给你发了一封电子邮件。现在让我编辑我的问题。 – WhiskerBiscuit

+0

仍不确定我明白。你写的一些东西(例如“在某些情况下,内部工作会根据持久性而改变”)听起来像是“产品”违反了Liskov替代原则(LSP)......如果“产品”需要根据它会违反LSP的具体类型'IUnitOfWork'。如果是这样的话,那听起来这个部分应该被重构为多态策略。你可能会发布一个'Add'方法的例子吗? –

回答

1

如果我理解这个正确的,你想要的客户端代码要做到这一点,当uow是基于SQL Server:

uow.ProductRepo.Insert(new UserModel(){..... 
uow.Save(); 
var uid = uow.ProductRepo.Get(u => u.someuniquecode == someUniqueCode)....... (etc) 

但是这时候它是基于一个测试替身:

var uid = uow.ProductRepo.Get(some lambda to get the largest ID) + 1 
uow.ProductRepo.Insert(new UserModel(ID = uid, ....... 

但是,这不是多态的行为。它违反了Open Closed Principle,因为它要求客户知道可用的实现方式,它可能也违反了Liskov Substitution Principle,尽管我对此不太确定。

为什么不使用生产交互,然后为两个库正确实施IUnitOfWork

如果你真的必须有这种不同的行为,那么你应该隐藏Strategy后面这些差异,而这又可以作为Facade Service超过IUnitOfWork行动。然后将该门面服务注入Products而不是IUnitOfWork

相关问题