سؤال

Let me begin by saying I am a mathematician and not a coder. I am trying to code a linear solver. There are 10 methods which I coded. I want the user to choose which solver she wishes to use, like options.solver_choice='CG'.

Now, I have all 10 methods coded in a single class. How do I use the strategy pattern in this case?

Previously, I had 10 different function files which I used to use in the main program using a switch case.

if options.solver_choice=='CG'
CG(A,x,b);
if options.solver_choice=='GMRES'
GMRES(A,x,b);
.
.
.
هل كانت مفيدة؟

المحلول 3

Other answers present the pattern correctly, however I don't feel they are clear enough. Unfortunately the link I've provided does the same, so I'll try to demonstrate what's the Strategy's spirit, IMHO.

Main thing about strategy is to have a general procedure, with some of its details (behaviours) abstracted, allowing them to be changed transparently.

Consider an gradient descent optimization algorithm - basically, it consists of three actions:

  • gradient estimation
  • step
  • objective function evaluation

Usually one chooses which of these steps they need abstracted and configurable. In this example it seems that evaluation of the objective function is not something that you can do in more than one way - you always just ... evaluate the function.

So, this introduces two different strategy (or policy) families then:

interface GradientStrategy
{
  double[] CalculateGradient(Function objectiveFunction, double[] point);
}

interface StepStrategy
{
  double[] Step(double[] gradient, double[] point);
}

where of course Function is something like:

interface Function
{
  double Evaluate(double[] point);
}

interface FunctionWithDerivative : Function
{
  double[] EvaluateDerivative(double[] point);
}

Then, a solver using all these strategies would look like:

interface Solver
{
  double[] Maximize(Function objectiveFunction);
}

class GradientDescentSolver : Solver
{
  public Solver(GradientStrategy gs, StepStrategy ss)
  {
    this.gradientStrategy = gs;
    this.stepStrategy = ss;
  }

  public double[] Maximize(Function objectiveFunction)
  {
    // choosing starting point could also be abstracted into a strategy
    double[] currentPoint = ChooseStartingPoint(objectiveFunction);
    double[] bestPoint = currentPoint; 
    double bestValue = objectiveFunction.Evaluate(bestPoint);

    while (...) // termination condition could also 
                // be abstracted into a strategy
    {
      double[] gradient = this.gradientStrategy.CalculateGradient(
                            objectiveFunction,
                            currentPoint);

      currentPoint = this.stepStrategy.Step(gradient, currentPoint);

      double currentValue = objectiveFunction.Evaluate(currentPoint);

      if (currentValue > bestValue)
      {
        bestValue = currentValue;
        bestPoint = currentPoint;
      }
      else
      {
        // terminate or step back and reduce step size etc.
        // this could also be abstracted into a strategy
      }
    }

    return bestPoint;
  }

  private GradientStrategy gradientStrategy;
  private StepStrategy stepStrategy;
}

So the main point is that you have some algorithm's outline, and you delegate particular, general steps of this algorithm to strategies or policies. Now you could implement GradientStrategy which works only for FunctionWithDerivative (casts down) and just uses function's analytical derivative to obtain the gradient. Or you could have another one implementing stochastic version of gradient estimation. Note, that the main solver does not need to know about how the gradient is being calculated, it just needs the gradient. The same thing goes for the StepStrategy - it can be a typical step policy with single step-size:

class SimpleStepStrategy : StepStrategy
{
  public SimpleStepStrategy(double stepSize)
  { 
    this.stepSize = stepSize;
  }

  double[] Step(double[] gradient, double[] point)
  {
    double[] result = new double[point.Length];

    for (int i = 0;i < result.Length;++i)
    {
      result[i] = point[i] + this.stepSize * gradient[i]; 
    }

    return result;
  }

  private double stepSize;
}

, or a complicated algorithm adjusting the step-size as it goes.

Also think about the behaviours noted in the comments in the code: TerminationStrategy, DeteriorationPolicy.

Names are just examples - they're probably not the best, but I hope they give the intent. Also, usually best to stick with one version (Strategy or Policy).

نصائح أخرى

This isn't the most exact of answers, but you should get the idea.

Using the strategy pattern, you would have a solver interface that implements a solver method:

public interface ISolver {

    int Solve();

}

You would implement each solver class as necessary:

public class Solver1 : ISolver {

    int Solve() {
        return 1;
    }

}

You would then pass the appropriate solver class when it's time to do the solving:

public int DoSolve(ISolver solver) {
    return solver.solve();
}

Foo.DoSolve(new Solver1());

TL;DR

As I've always understood the strategy pattern, the idea is basically that you perform composition of a class or object at run-time. The implementation details vary by language, but you should be able to swap out pieces of behavior by "plugging in" different modules that share an interface. Here I present an example in Ruby.

Ruby Example

Let's say you want to use select a strategy for how the #action method will return a set of results. You might begin by composing some modules named CG and GMRES. For example:

module CG
  def action a, x, b
    { a: a, x: x, b: b }
  end
end

module GMRES
  def action a, x, b
    [a, x, b]
  end
end

You then instantiate your object:

class StrategyPattern
end

my_strategy = StrategyPattern.new

Finally, you extend your object with the plug-in behavior that you want. For example:

my_strategy.extend GMRES
my_strategy.action 'q', nil, 1
#=> ["q", nil, 1]

my_strategy.extend GMRES
my_strategy.action 'q', nil, 1
#=> {:a=>"q", :x=>nil, :b=>1}

Some may argue that the Strategy Pattern should be implemented at the class level rather than by extending an instance of a class, but this way strikes me as easier to follow and is less likely to screw up other instances that need to choose other strategies.

A more orthodox alternative would be to pass the name of the module to include into the class constructor. You might want to read Russ Olsen's Design Patterns in Ruby for a more thorough treatment and some additional ways to implement the pattern.

PHP Examples

You'd define your strategies that implement only singular method called solve()

class CG
{
    public function solve($a, $x, $y)
    {
       //..implementation
    }
}

class GMRES
{
    public function solve($a, $x, $y)
    {
       // implementation..
    }
}

Usage:

$solver = new Solver();

$solver->setStratery(new CG());
$solver->solve(1,2,3); // the result of CG

$solver->setStrategy(new GMRES());
$solver->solve(1,2,3); // the result of GMRES

class Solver
{
     private $strategy;
     
     public function setStrategy($strategy)
     {
         $this->strategy = $strategy;
     }

     public function solve($a, $x, $y)
     {
         return $this->strategy->solve($a, $x, $y);
     }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top