温莎城堡抽象工厂
Castle Windsor Abstract Factory
我正在尝试了解如何使用 TypedFactoryFacility
创建一个抽象工厂,并且我在基础级别上使用它,但是我不完全了解如何使用 [=82] 对其进行扩展=]时间依赖性
假设我有一个服务需要在运行时间创建:
public interface IRuntimeService {
void DoThing();
}
使用以下实现
public class RuntimeService : IRuntimeService {
public void DoThing() {
// Do some work
}
}
为了创建我的 IRuntimeService
,我创建了一个抽象工厂
public interface IRuntimeServiceFactory {
IRuntimeService CreateService();
}
在我的 Castle 安装程序中,我使用 TypedFactoryFacility
注册我的 class 和抽象工厂。
public class TypeInstaller : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IRuntimeService>().ImplementedBy<RuntimeService>());
container.Register(Component.For<IRuntimeServiceFactory>().AsFactory());
}
然后在我的 class 中将使用该服务,我可以使用工厂在 运行 时间创建新的服务实例。
var myService = m_ServiceFactory.CreateService();
上面的一切都完美,但是当我的 RuntimeService
class 需要注入时,我 运行 遇到了问题包含 运行 时间参数的依赖链本身。
为了扩展上面的例子,假设我有一个新的运行时间依赖
public interface IRuntimeDependency {
void DoWork();
}
由 class 实现,它通过构造函数获取 运行 时间字符串值
public class RuntimeDependency : IRuntimeDependency {
private readonly string m_Param;
public RuntimeDependency(string param) {
m_Param = param;
}
public void DoWork() {
// Do work involving the param
}
}
之前定义的服务class现在需要引用依赖关系
public class RuntimeService : IRuntimeService {
private readonly IRuntimeDependency m_Dep;
public RuntimeService(IRuntimeDependency dep) {
m_Dep = dep;
}
public void DoThing() {
// Do some work involving the dependency
m_Dep.DoWork();
}
}
我现在如何使用 TypedFactoryFacility
创建我的服务实例?
我希望能够将我的工厂方法更改为
IRuntimeService CreateService(string param);
但 Windsor 抛出错误“无法解析参数 'param' 类型 'System.String' 的非可选依赖项。
如果我给它一个字符串,Windsor 知道如何创建一个 IRuntimeDependency
,如果我给它依赖,它知道如何创建一个 IRuntimeService
,为什么它不能直接创建带有字符串参数的 IRuntimeService
?
我可以通过两个不同的工厂方法让它工作
IRuntimeService CreateService(IRuntimeDependency dep);
IRuntimeDependency CreateDependency(string param);
我自己手动创建依赖关系
var dep = m_ServiceFactory.CreateDependency(param);
var myService = m_ServiceFactory.CreateService(dep );
^^^这有效,但使用容器的全部意义在于它会为我组装新对象。这是一个相对简单的示例,仅涉及一个依赖项,但如果使用更复杂的对象图,它很容易失去控制。
我当然可以创建自己的工厂实现,但这也抵消了使用 TypedFactoryFacility
的好处,它应该为您创建抽象工厂实现。我很难相信这个问题没有现成的解决方案,但 Windsor 示例不包含任何链式 运行-time 依赖项。
我认为使用 FactoryComponentSelector
不是正确的方法,因为只有一种可能的路径可以创建 RuntimeService
实例。应该可以自动解析。
在许多或大多数情况下,由容器解析的对象依赖于同样由容器解析的其他接口的实现。所以只要所有的接口都注册了实现,容器就可以解析整个依赖链。
但在这种情况下 RuntimeDependency
取决于字符串,这不是容器可以解析的内容。
public RuntimeDependency(string param) {
m_Param = param;
}
在这种情况下,您可以使用 DependsOn
方法显式提供一个值来实现该依赖关系。
container.Register(Component.For<IRuntimeDependency, RuntimeDependency>()
.DependsOn(Dependency.OnValue("param","whatEverTheValueIs")));
当然,该值可以来自配置或其他任何地方。我经常使用 SQL 连接字符串。
看来我所要求的是设计上无法实现的。
查看其他 SO 答案。
可以使用 DynamicParameters。
container.Register(Component.For<IRuntimeService>()
.ImplementedBy<RuntimeService>()
.LifestyleTransient()
.DynamicParameters((k, d) => {
d["dep"] = new RuntimeDependency((string)d["param"]);
}));
请记住,字典键必须与 CreateService
方法和 RuntimeService
构造函数中的参数名称相匹配。
编辑: 如果您打算在每次调用工厂方法时创建一个新实例,您也应该将其设置为 LifestyleTransient。 (默认为单例)
我正在尝试了解如何使用 TypedFactoryFacility
创建一个抽象工厂,并且我在基础级别上使用它,但是我不完全了解如何使用 [=82] 对其进行扩展=]时间依赖性
假设我有一个服务需要在运行时间创建:
public interface IRuntimeService {
void DoThing();
}
使用以下实现
public class RuntimeService : IRuntimeService {
public void DoThing() {
// Do some work
}
}
为了创建我的 IRuntimeService
,我创建了一个抽象工厂
public interface IRuntimeServiceFactory {
IRuntimeService CreateService();
}
在我的 Castle 安装程序中,我使用 TypedFactoryFacility
注册我的 class 和抽象工厂。
public class TypeInstaller : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IRuntimeService>().ImplementedBy<RuntimeService>());
container.Register(Component.For<IRuntimeServiceFactory>().AsFactory());
}
然后在我的 class 中将使用该服务,我可以使用工厂在 运行 时间创建新的服务实例。
var myService = m_ServiceFactory.CreateService();
上面的一切都完美,但是当我的 RuntimeService
class 需要注入时,我 运行 遇到了问题包含 运行 时间参数的依赖链本身。
为了扩展上面的例子,假设我有一个新的运行时间依赖
public interface IRuntimeDependency {
void DoWork();
}
由 class 实现,它通过构造函数获取 运行 时间字符串值
public class RuntimeDependency : IRuntimeDependency {
private readonly string m_Param;
public RuntimeDependency(string param) {
m_Param = param;
}
public void DoWork() {
// Do work involving the param
}
}
之前定义的服务class现在需要引用依赖关系
public class RuntimeService : IRuntimeService {
private readonly IRuntimeDependency m_Dep;
public RuntimeService(IRuntimeDependency dep) {
m_Dep = dep;
}
public void DoThing() {
// Do some work involving the dependency
m_Dep.DoWork();
}
}
我现在如何使用 TypedFactoryFacility
创建我的服务实例?
我希望能够将我的工厂方法更改为
IRuntimeService CreateService(string param);
但 Windsor 抛出错误“无法解析参数 'param' 类型 'System.String' 的非可选依赖项。
如果我给它一个字符串,Windsor 知道如何创建一个 IRuntimeDependency
,如果我给它依赖,它知道如何创建一个 IRuntimeService
,为什么它不能直接创建带有字符串参数的 IRuntimeService
?
我可以通过两个不同的工厂方法让它工作
IRuntimeService CreateService(IRuntimeDependency dep);
IRuntimeDependency CreateDependency(string param);
我自己手动创建依赖关系
var dep = m_ServiceFactory.CreateDependency(param);
var myService = m_ServiceFactory.CreateService(dep );
^^^这有效,但使用容器的全部意义在于它会为我组装新对象。这是一个相对简单的示例,仅涉及一个依赖项,但如果使用更复杂的对象图,它很容易失去控制。
我当然可以创建自己的工厂实现,但这也抵消了使用 TypedFactoryFacility
的好处,它应该为您创建抽象工厂实现。我很难相信这个问题没有现成的解决方案,但 Windsor 示例不包含任何链式 运行-time 依赖项。
我认为使用 FactoryComponentSelector
不是正确的方法,因为只有一种可能的路径可以创建 RuntimeService
实例。应该可以自动解析。
在许多或大多数情况下,由容器解析的对象依赖于同样由容器解析的其他接口的实现。所以只要所有的接口都注册了实现,容器就可以解析整个依赖链。
但在这种情况下 RuntimeDependency
取决于字符串,这不是容器可以解析的内容。
public RuntimeDependency(string param) {
m_Param = param;
}
在这种情况下,您可以使用 DependsOn
方法显式提供一个值来实现该依赖关系。
container.Register(Component.For<IRuntimeDependency, RuntimeDependency>()
.DependsOn(Dependency.OnValue("param","whatEverTheValueIs")));
当然,该值可以来自配置或其他任何地方。我经常使用 SQL 连接字符串。
看来我所要求的是设计上无法实现的。
查看其他 SO 答案。
可以使用 DynamicParameters。
container.Register(Component.For<IRuntimeService>()
.ImplementedBy<RuntimeService>()
.LifestyleTransient()
.DynamicParameters((k, d) => {
d["dep"] = new RuntimeDependency((string)d["param"]);
}));
请记住,字典键必须与 CreateService
方法和 RuntimeService
构造函数中的参数名称相匹配。
编辑: 如果您打算在每次调用工厂方法时创建一个新实例,您也应该将其设置为 LifestyleTransient。 (默认为单例)