views:

179

answers:

3

In the application I am developing I am facing a situation; I want to know if there is a design pattern for this. It's as follows

  1. User is presented on a web interface with different algorithms for a process
  2. User selection is stored in the database.
  3. Now, the application should perform computations differently depending on the algorithm selected.

What is a good strategy to implement this? Right now what we are doing is -

  1. Have a reference DB table which has all the algorithm types and the corresponding class names in code (eg. If quick sort algorithm then we store QuickSort). This has to be manually updated everytime a new algo comes
  2. In the code, get the algorithm type and use reflection to instantiate the appropriate algorithm type. In C# we use code similar to below

    System.Reflection.Assembly types = System.Reflection.Assembly.LoadFile(System.Reflection.Assembly.GetExecutingAssembly().Location.ToString());
    foreach (Type t in types) if (t.Name==classname) createinstanceof(t) //classnames is the list of all the class types that is loaded from reference table in DB.

My gut feeling is there should be a simpler/better way to do this as it seems a very standard problem. I know the strategy pattern - but what I want is to simplify and possibly remove manual tasks.

+2  A: 

Yeah, you're right, what you want is the Strategy pattern. What you really want to do, though, is define an interface which each of your algorithms uses that allows you to specify the parameters for your algorithm and which allows you to invoke each of them simply through the interface, instead of the ugly reflection process you describe in the question.

McWafflestix
+1 - Beat me to it :)
Russ Cam
I would argue that what satyajit has done kind of is an implementation of Strategy. It may or may note use a common interface.
Torbjørn
@Torb0rn: I don't disagree that what the OP did is an implementation of Strategy; he specifically asked for a simpler / better way, which I think defining an interface to manage the strategies would be.
McWafflestix
A: 

Use the Factory design and the Strategy design as follows

public interface ISorter {
   // Prototype for your sort function goes here
}

public class QuickSorter implements ISorter {}

public class SorterFactory {
   public ISorter getSorter( string sortType ) {
      // Return the correct type of sorting algorithm
      if ( sortType.equals( "QuickSort" ) ) {
         return new QuickSorter();
      }
   }
}

Then you just lookup what the user selected in the database and pass that in as the parameter to the factory.

NOTE TO MOD: Don't edit Java code if you don't know the correct syntax, unless you thought that this was C#, either way is fine by me.

DevDevDev
Haven't you just replaced satyajit's reflection with a switch/if-else? I agree that this smells of Strategy, but it does not improve the situation very much.. You have just added one more place (the factory) where the code needs to change if more strategies are added.
Torbjørn
Yes Torbjorn, in code as well as in database. That is what I want to eliminate. Can someone understand my pain, today I created a new algorithm like CBigBadSortingAlgorithm.cs and I have to go to backend and add this name in database. I am afraid, what happens if the schema changes in future, who will track all this?
satyajit
Why is he adding the names to the database? Why not assign a string depending on which checkbox is clicked and pass that into the factory?
DevDevDev
+2  A: 

You can use Interface + Reflection to avoid storing algorithm names in database.

Create an Interface IMySortingAlgorithms as,

public interface IMySortingAlgorithms
    {
        string Name { get; }
        string[] Sort(string[] input);
    }

Now, write a Factory that uses reflection to get the sorting algorithm.

public static class MyAlgoFactory
{
    private static Dictionary<string, IMySortingAlgorithms> m_dict;

    /// <summary>
    /// For all the assmeblies in the current application domain,
    /// Get me the object of all the Types that implement IMySortingAlgorithms
    /// </summary>
    static MyAlgoFactory()
    {
        var type = typeof(IMySortingAlgorithms);
        m_dict = AppDomain.CurrentDomain.GetAssemblies().
            SelectMany(s => s.GetTypes()).
            Where(p => {return type.IsAssignableFrom(p) && p != type;}).
            Select(t=> Activator.CreateInstance(t) as IMySortingAlgorithms).
            ToDictionary(i=> i.Name);
    }

    public static IMySortingAlgorithms GetSortingAlgo(string name)
    {
        return m_dict[name];
    }
}

All your sorting algorithms can now implement this interface.

 public class MySortingAlgo1 : IMySortingAlgorithms
    {
        #region IMySortingAlgorithms Members

        public string Name
        {
            get { return "MySortingAlgo1"; }
        }

        public string[] Sort(string[] input)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

This way you need not add the class names to database whenever you create a new class for sorting.

Following is the non-Linq version of MyAlgoFactory

    /// <summary>
    /// For all the assmeblies in the current application domain,
    /// Get me the object of all the Types that implement IMySortingAlgorithms
    /// </summary>
   static MyAlgoFactory()
        {
            m_dict = new Dictionary<string, IMySortingAlgorithms>();
            var type = typeof(IMySortingAlgorithms);
            foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
            {
                foreach (Type p in asm.GetTypes())
                {
                    if (type.IsAssignableFrom(p) && p != type)
                    {
                        IMySortingAlgorithms algo = Activator.CreateInstance(p)
                              as IMySortingAlgorithms;
                        m_dict[algo.Name] = algo;
                    }
                }
            }
        }
chikak
Wow this seems to be leading somewhere! , but what I do not understand is, how can I know at run time what selection the user has made? I mean, its a web interface and I have to store values(for re-runs) etc.. Specifically, public static IMySortingAlgorithms GetSortingAlgo(string name) how can I know the parameter name at run time?
satyajit
With some modifications, I was able to use this pattern in my code. Thanks, Pradeep :)
satyajit