策略模式如何工作?

How does the Strategy Pattern work?

它是如何工作的,用途是什么,何时应使用它?


让我们以简单的方式来说明策略模式:

您有一个带有方法run()的类Car(),因此您可以在伪语言中以这种方式使用它:

1
2
mycar = new Car()
mycar.run()

现在,您可能想在程序执行时即时更改run()行为。例如,您可能想模拟电动机故障或在视频游戏中使用"升压"按钮。

有几种方法可以进行此模拟:使用条件语句和标志变量是一种方法。策略模式是另一种:将run()方法的行为委托给另一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Class Car()
{
    this.motor = new Motor(this)

    // passing"this" is important for the motor so it knows what it is running

    method run()
    {
        this.motor.run()
    }

    method changeMotor(motor)
    {
        this.motor = motor
    }

}

如果要更改汽车的性能,则只需更改电动机即可。 (在程序中比在现实生活中容易,对吗?;-))

如果您有很多复杂的状态,这将非常有用:您可以更轻松地进行更改和维护。


问题

策略模式用于解决可能(或预见到可能)通过不同策略实施或解决的问题,并且这些问题具有明确定义的界面。每种策略本身都是完全有效的,其中某些策略在某些情况下更可取,从而允许应用程序在运行时在它们之间进行切换。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
namespace StrategyPatterns
{
  // Interface definition for a Sort algorithm
  public interface ISort
  {
    void Sort(List<string> list)
  }

  // QuickSort implementation
  public class CQuickSorter : ISort
  {
    void Sort(List<string> list)
    {
      // Here will be the actual implementation
    }
  }

  // BubbleSort implementation
  public class CBubbleSort : ISort
  {
    void Sort(List<string> list)
    {
      // The actual implementation of the sort
    }
  }

  // MergeSort implementation
  public class CMergeSort : ISort
  {
    void Sort(List<string> list)
    {
      // Again the real implementation comes here
    }
  }

  public class Context
  {
    private ISort sorter;

    public Context(ISort sorter)
    {
      // We pass to the context the strategy to use
      this.sorter = sorter;
    }

    public ISort Sorter
    {
      get{return sorter;)
    }
  }

  public class MainClass
  {
    static void Main()
    {
       List<string> myList = new List<string>();

       myList.Add("Hello world");
       myList.Add("Another item");
       myList.Add("Item item");

       Context cn = new Context(new CQuickSorter());
       // Sort using the QuickSort strategy
       cn.Sorter.Sort(myList);
       myList.Add("This one goes for the mergesort");
       cn = new Context(new CMergeSort());
       // Sort using the merge sort strategy
       cn.Sorter.Sort(myList);
    }
  }
}


  • 什么是策略?战略是旨在实现特定目标的行动计划;
  • "定义一系列算法,封装每个算法,并使它们可互换。策略使算法独立于使用该算法的客户端而变化。"(四人制);
  • 指定一组类,每个类代表一种潜在的行为。在这些类之间切换会更改应用程序的行为。 (该策略);
  • 可以在运行时(使用多态)或设计时进行选择。
  • 在接口中捕获抽象,将实现细节埋在派生类中;

enter image description here

  • 该策略的替代方法是通过使用条件逻辑来更改应用程序行为。 (坏);
  • 使用此模式使添加或删除特定行为变得更加容易,而无需重新编码和重新测试应用程序的全部或部分。

  • 良好的用途:

    • 当我们有一组相似的算法时,需要在应用程序的不同部分之间进行切换。使用策略模式可以避免故障并简化维护;
    • 当我们想为超类添加不一定对每个子类都有意义的新方法时。代替以传统方式使用接口,而是添加新方法,我们使用实例变量,该实例变量是新Functionality接口的子类。这称为组合:类不是通过继承来继承功能,而是由具有适当功能的对象组成;

密切相关的模式是"委托"模式。在这两种情况下,某些工作都会传递给其他组件。如果我正确理解,则这些模式之间的区别是这样(如果我错了,请纠正我):

  • 在Delegate模式中,委托是通过封闭(委托)类实例化的;这允许通过组合而不是继承来重用代码。封闭的类可能知道委托人的具体类型,例如如果它本身调用其构造函数(而不是使用工厂)。

  • 在策略模式中,执行策略的组件是通过其构造函数或设置器(根据您的信仰)提供给封闭(使用)组件的依赖项。使用组件完全不知道正在使用什么策略。该策略始终通过接口调用。

有人知道其他区别吗?


直接来自Strategy Pattern Wikipedia文章:

The strategy pattern is useful for situations where it is necessary to dynamically swap the algorithms used in an application. The strategy pattern is intended to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms vary independently from clients that use them.


要添加到已经精妙的答案中:策略模式与将一个(或多个)函数传递给另一个函数有很大的相似性。在该策略中,这是通过将所述函数包装在对象中,然后传递对象来完成的。某些语言可以直接传递函数,因此它们根本不需要模式。但是其他语言不能传递函数,但是可以传递对象。该模式将适用。

尤其是在类似Java的语言中,您会发现该语言的类型库非常小,并且扩展它的唯一方法是创建对象。因此,大多数解决问题的方法都是提出一种模式。一种组合对象以实现特定目标的方法。动物园类型丰富的语言通常具有解决问题的简单方法-但是类型丰富也意味着您必须花费更多的时间来学习类型系统。具有动态打字规则的语言通常也可以轻松地解决问题。


推荐阅读