其他答案正确地呈现了模式,但我觉得它们不够清楚。不幸的是,我提供的链接也是如此,所以我将尝试展示该战略的精神,恕我直言。
策略的主要内容是有一个通用程序,其中一些细节(行为)被抽象化,允许透明地更改它们。
考虑一个梯度下降优化算法——基本上,它由三个动作组成:
通常人们选择他们需要抽象和可配置的这些步骤中的哪一个。在这个例子中,目标函数的评估似乎不是你可以用不止一种方式做的事情——你总是只是……评估函数。
因此,这引入了两个不同的策略(或策略)系列:
interface GradientStrategy
{
double[] CalculateGradient(Function objectiveFunction, double[] point);
}
interface StepStrategy
{
double[] Step(double[] gradient, double[] point);
}
当然Function
是这样的:
interface Function
{
double Evaluate(double[] point);
}
interface FunctionWithDerivative : Function
{
double[] EvaluateDerivative(double[] point);
}
然后,使用所有这些策略的求解器将如下所示:
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;
}
所以重点是你有一些算法的大纲,你把这个算法的特定的、一般的步骤委托给策略或策略。现在您可以实现GradientStrategy
仅适用于FunctionWithDerivative
(向下投射)的方法,并且只使用函数的解析导数来获得梯度。或者你可以让另一个实现梯度估计的随机版本。注意,主求解器不需要知道梯度是如何计算的,它只需要梯度。同样的事情StepStrategy
- 它可以是一个典型的单步长策略:
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;
}
,或者是一个复杂的算法来调整步长。
还要考虑代码中注释中提到的行为:TerminationStrategy
, DeteriorationPolicy
.
名字只是例子——它们可能不是最好的,但我希望它们能给出意图。此外,通常最好坚持使用一个版本(策略或策略)。