【发布时间】:2014-05-13 09:03:43
【问题描述】:
情况
我最近将我的主要 Big Blob 域类型重构为外观,因为它具有各个方面。到目前为止,立面和各个方面的服务都像魅力一样工作,但创建整个事物并将所有内容连接在一起是在 Big Blob Factory 中为Poor Man's Dependency Injection 类型完成的。不得不手动将整个东西放在一起真的很烦人,所以我觉得我已经将 Big Blob Domain 类型换成了 Big Blog Domain 类型工厂:-/。
我正在尝试关注SOLID Principles,到目前为止,由于QueryHandler 和CommandHandler 抽象以及我最喜欢的依赖注入容器(@987654325),域与我的视图层的连接工作得非常好@)。
现在我想知道如何利用SimpleInjector 来完成我的大型工厂手工完成的工作。
一些示例代码来说明我的案例
请注意,实际的IUser 是由其他地方的单独工厂创建的,并作为Command/Query 参数对象的属性提交,因此在我的书中它不被视为服务(例如由 DI 容器提交),而是作为数据。
重构之前:
class BigDomainBlob : IDomainService
{
public BigDomainBlob(Config config)
{
// Set up all the big blog business with the help of the
// given configuration ...
}
// Lots of code interleaving the various aspects of the domain
}
interface IUser : System.Security.Principal.IPrincipal
{
// Session information, ip address, etc.
}
class BigDomainBlobFactory : IFactory<IUser, IDomainService>
{
// To this point the DI container can help me autowire the
// factory's dependencies
public BigDomainBlobFactory(/* ... */)
{
// Injecting persistence strategies and client specific
// plugins to customize the service creation
}
public IDomainService Create(IUser user)
{
return new BigDomainBlob(new BigDomainBlob.Config
{
// Plenty of configuration code to tailor
// the service to the needs of the given user
});
}
}
重构后:
class NeatDomainFacade : IDomainService
{
private readonly IDataHandlingService service1;
private readonly IMetaDataService service2;
public NeatDomainFacade(
IDataHandlingService service1,
IMetaDataService service2)
{
this.service1 = service1;
this.service2 = service2;
}
// Forwarding the IDomainService functionality
// to the different aspects of the domain
}
class NeatDomainFacadeFactory : IFactory<IUser, IDomainService>
{
// To this point the DI container can still help me autowire the
// factory's dependencies
public NeatDomainFacadeFactory(/* ... */)
{
// Injecting persistence strategies and client specific
// plugins to customize the service creation
}
// I still have to tailor every aspect of the domain to the
// specific needs of a user by hand so the factory is going nuts
public IDomainService Create(IUser user)
{
// From here on I'm on my own hand wiring everything together ...
// ...
// Lots of code to set up user role, tailor SQL queries, etc.
// ...
// Handwiring my aspect dependencies and handing them in
// to my fresh domain service
var handWiredServiceForDataHandling = new Internal.DataService(
someServiceDependency,
anotherServiceDependency,
new Internal.DataService.Config
{
SomeUserSpecificDbQueryString = "..."
});
var handWiredServiceThatAlsoUsesDataHandling = new Internal.MetaDataService(
handWiredServiceForDataHandling,
yetAnotherServiceDependency,
new Internal.MetaDataService.Config
{
CustomizedMetaDataRetrievalString = "..."
});
// Even more code to hand wire and configure other dependencies ...
// Finally handing in the service dependencies and creating the domain service
return NeatDomainFacade(
handWiredServiceForDataHandling,
handWiredServiceThatAlsoUsesDataHandling);
}
}
问题
所以你看:所有不同的方面不仅需要其他服务,还需要一些数据配置来为用户定制他们的行为,所以所有这些都必须在用户信息可用的阶段进行配置——这意味着我可以' t 在启动时配置它们。 我以为我现在已经了解了依赖注入的方式,但我只是不明白如何在自动布线的帮助下实现这一点。
我已成功注入并使用工厂在我的QueryHandlers/CommandHandlers 中创建域服务,就像我说的:应用程序架构的其余部分似乎运行良好 - 我几乎没有要接触组合根,只需将依赖项放入构造函数并完成。要是我能解决这个 pita 域服务创建问题就好了:-)
帮助非常感谢!
编辑:
我做了 steven 在他的回答中建议的重构,但现在我面临着生活方式问题。在手工布线时,我为IDomainService 的每个实例创建了每个依赖项,并将它们重用于交叉依赖项。一些代码:
public IDomainService Create(IUser user)
{
// All dependencies are created exactly once and are
// being reused throughout this method
var serviceA = new ServiceA();
var serviceB = new ServiceB(serviceA);
var serviceC = new ServiceC(serviceA, serviceB)
return new DomainService(serviceA, serviceB, serviceC);
}
默认的Lifestyle.Transient 不再是这种情况,每个服务都将获得所请求依赖项的新实例。是否可以让 SimpleInjector 模拟我的手动接线行为?
再次感谢!
编辑2:
我使用 SimpleInjector LifetimeScope 是这样的:
public class CompositionRoot
{
public static Container container;
public sealed class DomainServiceFactory : IFactory<IDomainService>
{
public IDomainService Create()
{
var container = CompositionRoot.container;
using (container.BeginLifetimeScope())
{
return container.GetInstance<IDomainService>();
}
}
}
public static void Setup(Container container)
{
CompositionRoot.container = container;
container.Register<IDomainService, NeatDomainFacade>();
container.Register<IFactory<IDomainService>, DomainServiceFactory>();
container.RegisterLifetimeScope<ServiceA>();
container.RegisterLifetimeScope<ServiceB>();
container.RegisterLifetimeScope<ServiceC>();
}
}
现在我可以请求 IFactory<IDomainService> 并且生命周期范围正在为依赖项启动。终于免手动接线了:-)
【问题讨论】:
标签: c# dependency-injection refactoring factory simple-injector