我最近将我的主要Big Blob域类型重构为一个外观,因为它的各个方面。到目前为止,外观和各个方面的服务工作就像一个魅力,但创建整个事物并将所有内容连接在一起,在一个带有Poor Man's Dependency Injection类型的Big Blob Factory中完成。真的很烦人,不得不把整个东西放在一起,所以我觉得我已经为Big Blog Domain类型工厂交换了Big Blob Domain类型: - /。
我正在尝试关注SOLID Principles,到目前为止,由于QueryHandler和CommandHandler抽象以及我的最爱,域与我的视图层的连接确实非常有效依赖注入容器(SimpleInjector to the rescue)。
现在我想知道如何利用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在启动时配置它们。 我以为我现在已经开始依赖依赖注入方式了,但我不知道如何在自动布线的帮助下实现这一目标。
我已成功注入并使用工厂在我的QueryHandler
s / CommandHandler
中创建域服务,就像我说的那样:应用程序架构的其余部分似乎运行良好 - 我几乎不必触及组合根,只需将依赖项放入构造函数中并完成。如果我能解决这个皮塔域名服务的创建: - )
非常感谢帮助!
我在他的回答中提到了重构史蒂文,但现在我面临生活方式问题。虽然手工布线我为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模拟我的手工布线行为?
再次感谢!
我选择了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>
,并且生命周期范围正在为依赖项启动。最后没有手工布线: - )
答案 0 :(得分:2)
我认为问题在于您正在使用用户的上下文信息构建对象图。
因此,我建议不要这样做:
NeatDomainFacadeFactory.Create
方法传递用户信息,而是注入一个IUserContext
服务,允许在构建对象图之后检索IUser
。IUserContext
的额外服务,以便在运行时检索所需对象的正确信息。因此,不是为一个特定用户创建服务实例,而是创建一个可用于您正在运行的任何用户的实例,并且仅在您通过对象图实际发送runtim数据时根据用户做出决策(所以之后构造)。
你可能需要一些附加的重构来实现这个目的。