Ufuk Can Bicici
Ufuk Can Bicici

Reputation: 3659

What is a good design pattern for the following situation?

I have different string distance metric implementations at hand (all of them are in C#) for example, Levensthein, NeedlemanWunsch, Jaccard, etc. The job of these are same basically; take two strings as input and return a similarity score in the range [0,1]. So, I planned to make these classes to implement the same basic interface, as in the following:

public interface IStringDistanceMetric
{
    //Return a similarity between 0 and 1.
    double CompareSimilarity(string strA, string strB);
}

Each of my metrics will implement this method. But there are some metrics which will directly operate on two strings, without any other input and there are some metrics which needs some extra parameters( like the penalty given for a gap in one of the input strings, etc.). In general, I can give these parameters either in the constructor stage or just before calculating the similarity score.

My question is, in general, what would be a good design practice in order to handle such differences between the concrete distance classes? I aim that the client code which wants to use any distance metric should be oblivious to any underlying implementation detail, after it has decided use a specific kind of metric. The most obvious way would be to implement something like:

  IStringDistanceMetric metric;
  if(metricType == Metric.NeedlemanWunsch)
  {
    metric = new NeedlemanWunsch(parametersNW);
  }
  else if(metricType == Metric.Levensthein)
  {
    metric = new Levensthein(parametersL);
  }
  .
  . 
  .

But this doesn't look a good solution to me. I am kind of surprised to find myself stuck at such a basic looking design problem. Any help would be appreciated.

Upvotes: 4

Views: 227

Answers (2)

Bas
Bas

Reputation: 27115

I guess this is highly dependant on how it is used; are the values of these parameters fixed or should they be provided when doing the comparison? If the number of possible values for these parameters is very low, the design used in .NET for StringComparers could be followed (courtesy of 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;
    }
}

If you are getting user input or configuration settings to specify your parameter values, and they vary each time you compare strings, a factory method would probably be an appropriate solution, the 'most obvious way' presented in your answer.

Upvotes: 2

Patrick Hofman
Patrick Hofman

Reputation: 157136

If you want make no difference in the method signatures and want to hide the implementation details, the only option is to treat everything the same, that is, have one signature and parameterize it so one-fits-all.

You can think of supplying the metrics to the method using a class, or using a method containing all the fields. The implementation then decides what parameters are useful and takes those to do the calculations.

Upvotes: 1

Related Questions