使用静态工厂是依赖注入的有效模式吗?
Is using static factories a valid pattern for dependency injection?
我正在创建一个内部框架,有一次我想提供良好的可扩展性,支持一种依赖注入。
这是我在 .NET/C# 中的过滤模块的简化示例。假设有一个过滤器处理器组件,它接受 List
个对象,每个对象代表一个过滤条件。然后它的任务是 "translate" 这些到 Expressions 并将其应用于任何 IQueryable
。有一些简单的过滤器类型,例如 ColumnFilter,它引用字段名、运算符和一些操作数。但是,我想提供一种方法,让消费者可以通过自定义过滤条件来扩展过滤处理机制。所以我引入一个接口:
public interface IFilterProcessor {
Expression Process(FilterContext filter);
}
其中 FilterContext
包含当前处理的过滤器、根 ParameterExpression、根的类型 IQueryable
等信息,对于此示例不重要。
然后在某个时候可以定义一个新的过滤条件,并为其提供相应的IFilterProcessor
,并在那里实现条件的翻译。
我的想法来了,我会提供可扩展点作为静态可注册工厂,像这样:
public class FilterProcessor {
public static readonly Dictionary<Type, Func<IFilterProcessor>> ProcessorFactories = new ...
{
{typeof(ColumnFilter), () => new ColumnFilterProcessor() }
};
...
public Expression Process(object filterCondition) {
if (filterCondition == null) return null;
var factory = ProcessorFactories.GetValueOfDefault(filterCondition.GetType()); // my custom Dictionary extension to avoid exceptions and return null if no key found
if (factory == null) return null;
using (var processor = factory()) {
return processor.Process(filterCondition);
}
}
...
}
然后在应用程序的入口点,我可以 "register" 我的自定义过滤条件处理器,如下所示:
FilterProcess.ProcessorFactories[typeof(MyCustomCondition)] = () => ... get from Ninject for example ...;
使用此模式背后的想法是核心框架不必知道任何关于扩展的信息,类似于某些 "plugin" 系统。
请注意,这已大大简化,为清楚起见,省略了很多内容。实际上,例如我的过滤器可以分组、嵌套等,非常复杂。
现在我的问题是:
我已经阅读了很长时间有关设计模式的内容,尤其是 DI,但没有找到与此类似的示例。这是一个有效的、全球接受的模式吗?如果有的话,任何人都可以指出它的任何缺点吗?最后,如果这是一个有效的模式,它有名字吗?
通过使用 属性.
设置处理器,看起来你是在问而不是在说(http://en.wikipedia.org/wiki/Hollywood_principle)
我认为您可以通过更 'classic' DI 的方式实现相同的结果:使您的 FilterProcessor
依赖于 IFilterProcessor
的枚举,然后让 IoC 框架进行解析并通过注册 IFilterProcessors
为您注入。
我正在创建一个内部框架,有一次我想提供良好的可扩展性,支持一种依赖注入。
这是我在 .NET/C# 中的过滤模块的简化示例。假设有一个过滤器处理器组件,它接受 List
个对象,每个对象代表一个过滤条件。然后它的任务是 "translate" 这些到 Expressions 并将其应用于任何 IQueryable
。有一些简单的过滤器类型,例如 ColumnFilter,它引用字段名、运算符和一些操作数。但是,我想提供一种方法,让消费者可以通过自定义过滤条件来扩展过滤处理机制。所以我引入一个接口:
public interface IFilterProcessor {
Expression Process(FilterContext filter);
}
其中 FilterContext
包含当前处理的过滤器、根 ParameterExpression、根的类型 IQueryable
等信息,对于此示例不重要。
然后在某个时候可以定义一个新的过滤条件,并为其提供相应的IFilterProcessor
,并在那里实现条件的翻译。
我的想法来了,我会提供可扩展点作为静态可注册工厂,像这样:
public class FilterProcessor {
public static readonly Dictionary<Type, Func<IFilterProcessor>> ProcessorFactories = new ...
{
{typeof(ColumnFilter), () => new ColumnFilterProcessor() }
};
...
public Expression Process(object filterCondition) {
if (filterCondition == null) return null;
var factory = ProcessorFactories.GetValueOfDefault(filterCondition.GetType()); // my custom Dictionary extension to avoid exceptions and return null if no key found
if (factory == null) return null;
using (var processor = factory()) {
return processor.Process(filterCondition);
}
}
...
}
然后在应用程序的入口点,我可以 "register" 我的自定义过滤条件处理器,如下所示:
FilterProcess.ProcessorFactories[typeof(MyCustomCondition)] = () => ... get from Ninject for example ...;
使用此模式背后的想法是核心框架不必知道任何关于扩展的信息,类似于某些 "plugin" 系统。
请注意,这已大大简化,为清楚起见,省略了很多内容。实际上,例如我的过滤器可以分组、嵌套等,非常复杂。
现在我的问题是: 我已经阅读了很长时间有关设计模式的内容,尤其是 DI,但没有找到与此类似的示例。这是一个有效的、全球接受的模式吗?如果有的话,任何人都可以指出它的任何缺点吗?最后,如果这是一个有效的模式,它有名字吗?
通过使用 属性.
设置处理器,看起来你是在问而不是在说(http://en.wikipedia.org/wiki/Hollywood_principle)我认为您可以通过更 'classic' DI 的方式实现相同的结果:使您的 FilterProcessor
依赖于 IFilterProcessor
的枚举,然后让 IoC 框架进行解析并通过注册 IFilterProcessors
为您注入。