策略模式是如何工作的?

67

它是如何运作的,它有什么用途,以及什么时候应该使用它?


7
我建议阅读《Head First设计模式》的第1章。该章节对如何使用设计模式、为什么要使用它以及它是如何应用基本的面向对象原则进行了详细的解释。书中给出了一个具体(虽然有些有趣)的例子,展示了一个问题情境和策略模式如何解决该问题。 - user23163
6个回答

84

让我们通俗易懂地解释策略模式:

你有一个类 Car(),带有方法run(),在伪代码中可以这样使用:

mycar = new Car()
mycar.run()

现在,您可能想在程序执行时动态更改run()的行为。例如,您可能希望模拟电机故障或在视频游戏中使用“增强”按钮。

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

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 
    }

}

如果你想改变汽车的行为,只需更换电机即可。(在程序中比现实生活中容易多了,对吧?;-))

如果你有很多复杂状态,这就非常有用:你可以更轻松地改变和维护它们。


7
我喜欢这个答案,所以我投了赞成票,但我认为代码可以更加详细。 - Jorge Córdoba
我知道,这只是为了说明原理。读者可以在其他答案中找到大量准确的代码片段。 - Bite code
7
+1 好的例子!一个建议是在changeMotor()函数内加入stopMotor()函数,这样做只是为了好玩 :) - sll
7
我建议您也添加Motor类的代码,这有助于更好地理解整个情况。 - BornToCode
我很好奇为什么这里没有设计模式?我们能在实际工作中应用它吗,还是因为这只是一个例子? - Spring
如果Motor需要Car(因此您将“this”传递给它),当它作为参数传递给changeMotor时,如何优雅地传递Car? - BornToCode

41

问题

策略模式用于解决可能需要使用不同的策略来实现或解决,并且对于这些情况已经定义了明确定义的接口。每种策略本身都是完全有效的,其中某些策略在允许应用程序在运行时在它们之间切换的某些情况下更可取。

代码示例

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);
    }
  }
}

1
可能只是一个打字错误,但是你的CMergeSort类不应该实现ISort接口吗? - Andrew Swan
8
结构图已不可用,能否更新链接? - Thorkil Holm-Jacobsen
2
Context 类中拥有 get for ISort 的作用是什么?不确定在什么情况下会有用? - Billa
Sorter是私有的,我们可以使用cn.Sorter吗? - Jason Law

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

enter image description here

  • 与策略相反的一种方法是使用条件逻辑来更改应用程序行为(不好);
  • 使用该模式使得添加或删除特定行为更加容易,无需重新编写和重测整个应用程序或其部分。

  • 适用场景:

    • 当我们拥有一组相似的算法并且需要在应用程序的不同部分之间进行切换时。使用策略模式可以避免if语句并简化维护;
    • 当我们想要向超类添加不一定对每个子类都有意义的新方法时。但是,代替在传统方式下使用接口添加新方法,我们使用一个实例变量作为新功能接口的子类。这被称为组合:与其通过继承来继承能力,不如用具备正确能力的对象来组合类。

3
简单易懂的解释! - Pokuri
策略模式与依赖倒置原则有何不同? - piepi

7
一个密切相关的模式是委托模式;在这两种情况下,一些工作被传递给其他组件。如果我理解正确,这两种模式之间的区别是(如果我错了,请纠正我):
- 在“委托”模式中,委托由封装(委托)类实例化;这允许通过组合而非继承来重用代码。封装类可能知道委托的具体类型,例如,如果它自己调用其构造函数(而不是使用工厂)。 - 在“策略”模式中,执行策略的组件是通过其构造函数或设置器(根据您的信仰)提供给使用组件的依赖项。使用组件完全不知道正在使用哪种策略;策略始终通过接口调用。
有人知道其他区别吗?

6

直接摘自策略模式维基百科文章:

策略模式适用于需要动态交换应用程序中使用的算法的情况。 策略模式旨在提供一种定义算法族的方法,将每个算法封装为一个对象,并使它们可以互换。 策略模式使得算法可以独立于使用它们的客户端而变化。


5
除了已经给出的精彩回答,策略模式与将函数(或函数)传递给另一个函数有很强的相似之处。在策略中,这是通过将该函数包装在对象中,然后传递对象来完成的。一些语言可以直接传递函数,因此它们根本不需要该模式。但其他语言不能传递函数,但却可以传递对象;那么该模式就适用于这种情况。
特别是在类似Java的语言中,您会发现该语言的类型动物园非常小,扩展它的唯一方法是创建对象。因此,解决问题的大多数解决方案是想出一种模式;一种将对象组合起来以实现特定目标的方式。具有更丰富类型库的语言通常有更简单的解决问题的方式--但更丰富的类型也意味着您需要花更多时间学习类型系统。具有动态类型学科的语言也有一种巧妙地绕过该问题的方式。

1
"Type zoo" 是什么意思?它被证明是一个相当难以在谷歌上搜索到的术语。 - ftvs
1
这是一种像笑话一样的说法,意思是该语言没有非常表达能力强的类型系统。 - I GIVE CRAP ANSWERS

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接