我手头有不同的字符串距离度量实现(它们都在C#中),例如Levensthein、NeedlemanWunsch、Jaccard等。这些的工作基本上是相同的;将两个字符串作为输入并返回[0,1]范围内的相似性分数。所以,我计划让这些类实现相同的基本接口,如下所示:
public interface IStringDistanceMetric
{
//Return a similarity between 0 and 1.
double CompareSimilarity(string strA, string strB);
}
我的每个指标都会实现这个方法。但是有些指标会直接对两个字符串进行操作,而无需任何其他输入,并且有些指标需要一些额外的参数(例如对其中一个输入字符串中的间隙的惩罚等)。一般来说,我可以在构造器阶段或在计算相似性分数之前给出这些参数。
我的问题是,一般来说,为了处理具体距离类之间的这种差异,什么是一个好的设计实践?我的目标是,想要使用任何距离度量的客户端代码在决定使用特定类型的度量之后,应该忘记任何底层实现细节。最明显的方法是实现如下内容:
IStringDistanceMetric metric;
if(metricType == Metric.NeedlemanWunsch)
{
metric = new NeedlemanWunsch(parametersNW);
}
else if(metricType == Metric.Levensthein)
{
metric = new Levensthein(parametersL);
}
.
.
.
但这对我来说不是一个好的解决方案。我有点惊讶地发现自己被困在如此基本的设计问题上。任何帮助都将不胜感激。
我想这在很大程度上取决于它的使用方式;这些参数的值是固定的,还是应该在进行比较时提供?如果这些参数的可能值的数量非常少,可以遵循StringComparers中使用的设计。NET(由sourceof.net提供):
private static readonly StringComparer _invariantCulture = new CultureAwareComparer(CultureInfo.InvariantCulture, false);
private static readonly StringComparer _invariantCultureIgnoreCase = new CultureAwareComparer(CultureInfo.InvariantCulture, true);
private static readonly StringComparer _ordinal = new OrdinalComparer(false);
private static readonly StringComparer _ordinalIgnoreCase = new OrdinalComparer(true);
public static StringComparer InvariantCulture {
get {
return _invariantCulture;
}
}
如果您正在获取用户输入或配置设置来指定您的参数值,并且每次比较字符串时它们都会有所不同,那么工厂方法可能是一个合适的解决方案,即答案中呈现的“最明显的方式”。
如果您不想在方法签名中产生任何差异并想隐藏实现细节,唯一的选择是将所有内容都视为相同,即拥有一个签名并将其参数化为一刀切。
您可以考虑使用类或使用包含所有字段的方法向方法提供度量。然后实现决定哪些参数有用并使用这些参数进行计算。