I'm creating an internal framework, and at one point I would like to provide a good extensibility, supporting kind of dependecy injection.
Here is a simplified example of my filtering module in .NET/C#. Imagine there is a filter processor component, which takes a List of objects, each representing a filter condition. Then its task is "translate" these to Expressions and apply it to any IQueryable. There are trivial fitler types, for example a ColumnFilter, which refers to a fieldname, an operator, and some operands. However, I would like to provide a way to consumers to extend the filter processing mechanism with custom filter conditions. So I introduce an interface:
public interface IFilterProcessor {
Expression Process(FilterContext filter);
}
where FilterContext holds information like the currently processed filter, the root ParameterExpression, the Type of the root IQueryable, etc., not important for this example.
Then at some point one could define a new filter condition, and provide a corresponding IFilterProcessor to it, and implement the translation of the condition there.
And here comes my idea, I would provice the extensibility point as staticly registerable factories, something like this:
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);
}
}
...
}
Then at the entry point of the application I can "register" my custom filter condition processors like this:
FilterProcess.ProcessorFactories[typeof(MyCustomCondition)] = () => ... get from Ninject for example ...;
The idea behind using this pattern is that the core framework does not have to know anything about the extensions, similar to some "plugin" system.
Note that this is farly simplified and lot of things are omitted for clarity. In reality for example my filters can be grouped, nested, etc., whole lot complex.
And now my question: I've been reading for a long time about design patterns, especially DI, but haven't found any example similar to this one. Is this a valid, and globally accepted pattern? If there is any, could anyone point out any contras about it? Finally, if this is a valid pattern, does it have a name?
Aucun commentaire:
Enregistrer un commentaire