2014-10-27 42 views
4

我有不同的字符串距离度量实现手头(所有这些都在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); 
    } 
    . 
    . 
    . 

但是这对我来说不是一个好的解决方案。我有点惊讶地发现自己陷入了这样一个基本的外观设计问题。任何帮助,将不胜感激。

+3

你知道你要预先使用哪个吗?也许一个工厂会更适合在这里。这样客户端只需要一个实例,工厂方法就包含这个“if else”的东西并返回接口。这使得工厂可以访问参数的假设 - 它总是可以为这些参数提供参数。还允许您保留您的策略模式,以便返回接口的实现,这很好。 – 2014-10-27 13:07:14

+0

你试图做这件事的方式没有错,你有两个独立的alghorithms检查这两个字符串。让他们在不同的功能和使用if来选择你应该使用哪一个是正确的方式做到这一点。 – Vajura 2014-10-27 13:08:53

+0

同意@AdamHouldsworth。此外,我建议你的客户端代码将“stringDistanceMetric”_typed_作为接口(而不是实际的类类型),因此可以注入不同的具体类型。 – heltonbiker 2014-10-27 13:11:14

回答

2

我想这很大程度上取决于它是如何使用的;这些参数的值是固定的还是应该在进行比较时提供?如果可能值的这些参数的数量是非常低的,在.NET用于StringComparers的设计可以遵循(的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; 
    } 
} 

如果您收到用户输入或配置设置来指定参数值,而且每次比较字符串时它们都会有所不同,工厂方法可能是一个合适的解决方案,在您的答案中提供了“最明显的方式”。

+0

+1我没有想到这个解决方案,它确实是一个很好的解决方案。这确实存在一个问题,即调用者必须知道实现细节,这是我认为OP想要避免的。但那只是我的两分钱。 – 2014-10-27 13:22:47

+0

我认为可能需要经常更改参数。所以,一般来说,我应该有一个类:'StringMetricFactory',它接受所有相关参数,并生成我想要使用的度量类的具体实例,并将其作为对'IStringDistanceMetric'接口的引用返回。这是一个合适的解决方案? – 2014-10-27 13:24:41

+0

我这么认为,或者创建一个方法,返回所需的数据,并使用'Func GetMeThisMetrics'在'计算器'中'注入'。 – 2014-10-27 13:26:36

1

如果您希望在方法签名中没有任何区别,并希望隐藏实现细节,唯一的选择是将所有内容都对待,即拥有一个签名并对其进行参数化,以便适合所有人。

您可以考虑使用一个类或使用包含所有字段的方法将度量提供给方法。然后实现决定哪些参数是有用的,并将这些参数用于计算。

相关问题