获取适用的接口实现
Get applicable interface implementation
我正在尝试为我正在做的事情找到一个好的设计。例如,考虑接受字符串参数的 TextProcessor class 和 returns 返回已处理的字符串。
现在在我的实现中有许多不同的 TextProcessors,每个都能够处理自己定义的字符串集。每个处理器中有两个值得注意的方法:
bool CanProcess(string text);
和
string Process(string text);
实际上这些可以标记为 static 但为了实现通用接口,我没有将它们设置为 static。
除了这些 TextProcessors 之外,还有一个静态 TextProcessorFinder class。顾名思义,它会找到最好的 TextProcessor 并处理输入。
public static class TextProcessorFinder
{
private static List<ITextProcessor> _processors;
static TextProcessorFinder()
{
_processors = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(ITextProcessor))
&& t.IsClass && !t.IsAbstract)
.Select(t => (ITextProcessor)Activator.CreateInstance(t))
.Where(t => t.IsActive)
.ToList();
}
public static ITextProcessor GetTextProcessor(string text)
{
return _processors.Where(p => p.CanProcess(text))
.OrderByDescending(p => p.Priority)
.FirstOrDefault();
}
}
我讨厌这种方法的地方在于,我必须为每个已知的 TextProcessor 创建一个实例,只是为了调用它们的 CanProcess 函数。
我尝试用简单的 Func 创建一个属性来模拟 CanProcess 函数:
[AttributeUsage(AttributeTargets.Class)]
public class TextProcessorAttribute : Attribute
{
private Func<string, bool> func;
public TextProcessorAttribute(Func<string, bool> func)
{
this.func = func;
}
}
public interface ITextProcessor
{
bool IsActive { get; }
int Priority { get; }
bool CanProcess(string text);
string Process(string text);
}
// Hard-coded to true
[TextProcessor((s) => { return true; })]
public class SampleTextProcessor : ITextProcessor
{
// Implement ITextProcessor
}
遗憾的是,Func 不是有效的属性参数类型。
这样做的最佳方法是什么?
在我看来,创建这些实例是最好的方法。真的没有理由不这样做。实例很便宜,如果您不在构造函数中做任何工作,那么创建它们也很便宜——无论如何您都不应该这样做。
使用 CanProcess
方法,您可以询问每个派生的 ITextProcessor 是否可以处理文本。我认为这是可以的。
也许在 ITextProcessor 的实现中有某种专门化,在这种情况下,您可以创建更具体的接口,ITextTypeAProcessor、ITextTypeBProcessor 等。然后您可以在 GetTextProcessor
方法中按接口过滤。
我正在尝试为我正在做的事情找到一个好的设计。例如,考虑接受字符串参数的 TextProcessor class 和 returns 返回已处理的字符串。
现在在我的实现中有许多不同的 TextProcessors,每个都能够处理自己定义的字符串集。每个处理器中有两个值得注意的方法:
bool CanProcess(string text);
和
string Process(string text);
实际上这些可以标记为 static 但为了实现通用接口,我没有将它们设置为 static。
除了这些 TextProcessors 之外,还有一个静态 TextProcessorFinder class。顾名思义,它会找到最好的 TextProcessor 并处理输入。
public static class TextProcessorFinder
{
private static List<ITextProcessor> _processors;
static TextProcessorFinder()
{
_processors = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.GetInterfaces().Contains(typeof(ITextProcessor))
&& t.IsClass && !t.IsAbstract)
.Select(t => (ITextProcessor)Activator.CreateInstance(t))
.Where(t => t.IsActive)
.ToList();
}
public static ITextProcessor GetTextProcessor(string text)
{
return _processors.Where(p => p.CanProcess(text))
.OrderByDescending(p => p.Priority)
.FirstOrDefault();
}
}
我讨厌这种方法的地方在于,我必须为每个已知的 TextProcessor 创建一个实例,只是为了调用它们的 CanProcess 函数。
我尝试用简单的 Func 创建一个属性来模拟 CanProcess 函数:
[AttributeUsage(AttributeTargets.Class)]
public class TextProcessorAttribute : Attribute
{
private Func<string, bool> func;
public TextProcessorAttribute(Func<string, bool> func)
{
this.func = func;
}
}
public interface ITextProcessor
{
bool IsActive { get; }
int Priority { get; }
bool CanProcess(string text);
string Process(string text);
}
// Hard-coded to true
[TextProcessor((s) => { return true; })]
public class SampleTextProcessor : ITextProcessor
{
// Implement ITextProcessor
}
遗憾的是,Func 不是有效的属性参数类型。
这样做的最佳方法是什么?
在我看来,创建这些实例是最好的方法。真的没有理由不这样做。实例很便宜,如果您不在构造函数中做任何工作,那么创建它们也很便宜——无论如何您都不应该这样做。
使用 CanProcess
方法,您可以询问每个派生的 ITextProcessor 是否可以处理文本。我认为这是可以的。
也许在 ITextProcessor 的实现中有某种专门化,在这种情况下,您可以创建更具体的接口,ITextTypeAProcessor、ITextTypeBProcessor 等。然后您可以在 GetTextProcessor
方法中按接口过滤。