策略设计模式和状态设计模式有什么区别?

272

策略模式与状态模式之间有什么区别?我查阅了很多文章,但是仍然不能清楚地区分它们的不同。

请问有人能用通俗易懂的语言来解释它们之间的区别吗?


4
根据这里的回答和我的观察,似乎_实现_在很大程度上是相同的(尽管不完全相同)。相反,差异主要在于意图:我们试图通过状态(状态模式)或其他基础(策略模式)来适应行为。很多时候,这个“其他基础”是“客户选择的内容”,通过注入来实现。 - Timo
22个回答

5

策略模式和状态模式具有相同的结构。如果你查看这两种模式的UML类图,它们看起来完全相同,但它们的意图却完全不同。状态设计模式用于定义和管理对象的状态,而策略模式用于定义一组可互换的算法,并让客户端选择其中一个。因此,策略模式是一种客户端驱动的模式,而对象可以自己管理其状态。


4

状态模式的派生类之间存在一些依赖关系:例如,一个状态知道在它之后出现的其他状态。例如,对于任何季节状态,夏季在冬季之后,或者对于购物,交付状态在存款状态之后。

另一方面,策略模式没有这样的依赖关系。在这里,可以根据程序/产品类型初始化任何类型的状态。


3
两种模式都委托给一个具有多个派生类的基类,但只有在状态模式中,这些派生类保持对上下文类的引用。另一种看待它的方式是,策略模式是状态模式的简化版本;如果您喜欢,可以将其视为子模式。这实际上取决于您是否希望派生状态保持对上下文的引用(即,您是否希望它们调用上下文的方法)。
有关更多信息:Robert C Martin(& Micah Martin)在他们的书“Agile Principles,Patterns and Practices in C#”中回答了这个问题。 (http://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258)

3
这是一个相当老的问题,但我也在寻找同样的答案,这就是我发现的。对于状态模式,让我们考虑一个媒体播放器播放按钮的例子。当我们播放时,它开始播放并使上下文意识到它正在播放。每次客户端想执行播放操作时,它都会检查播放器的当前状态。现在客户端通过上下文对象知道对象的状态正在播放,因此调用暂停状态对象的操作方法。客户端实现状态以及需要执行操作的状态部分可以自动化。

https://www.youtube.com/watch?v=e45RMc76884 https://www.tutorialspoint.com/design_pattern/state_pattern.htm

在策略模式的情况下,类图的安排与状态模式相同。客户端使用此安排执行某些操作。换句话说,不同的状态变为不同的算法,例如需要对模式执行不同的分析。在这里,客户端告诉上下文它想要做什么算法(业务定义的自定义算法),然后执行该算法。

https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm

这两个模式都遵循开闭原则,因此开发者可以向状态模式和策略模式中添加新的状态和算法。

但是它们的区别在于,状态模式用于根据对象的状态执行不同的逻辑,而策略模式用于执行不同的逻辑。


3
简而言之,使用策略模式我们可以动态地设置一些行为,而使用状态模式,我们可以确保对象会随着其状态的变化而在内部改变其行为。

3
在我看来,它们的主要区别在于它们的意图。从技术上讲,“State”和“Strategy”模式看起来非常相似。主要区别在于:
  • 当需要更改状态时,“State”模式会更改上下文的状态,并且状态可以多次更改。所以上下文更改其状态或状态可以设置另一个状态
  • “Strategy”模式设置策略,策略很少更改,上下文不更改其策略

策略模式。

我们对一些声音策略的抽象:

public interface ISound
{
    void Make();
}   
    

它的具体策略:

public class DogSoundStrategy : ISound
{
    public void Make()
    {
        Console.WriteLine("Bar");
    }
}

public class CatSoundStrategy : ISound
{
    public void Make()
    {
        Console.WriteLine("Meow");
    }
}

这是一个能够发出声音的动物的抽象类:

public abstract class Animal
{
    public void MakeSound(ISound sound)
    {
        sound.Make();
    }
}

具体的动物长这样:

public class Dog : Animal
{
}

public class Cat : Animal
{   
}

然后我们可以像这样调用上面的代码:

Dog dog = new Dog();
dog.MakeSound(new DogSoundStrategy()); // there is a small chance 
    // that you want to change your strategy

Cat cat = new Cat();
cat.MakeSound(new CatSoundStrategy()); // there is a small chance 
    // that you want to change your strategy

有一定的可能性你想要改变你的策略

状态模式

假设你有一个电脑游戏,主人公可以是世界上任何超级人物,我们把他称为Hero, 他能够奔跑、游泳和飞行,并可以变形为IronManSpiderMan。您有一个按钮可以将其形状或状态更改为IronManSpiderMan

Hero 的代码看起来像这样:

public class Hero
{
    IState _state;

    public Hero()
    {
        _state = new SpiderManState();
    }

    public void Run()
    {
        _state.Run();
    }

    public void Swim()
    {
        _state.Swim();
    }

    public void Fly()
    {
        _state.Fly();
    }

    public void ChangeShape()
    {
        _state = _state.SetShape();
    }
}

IState接口的外观如下:

public interface IState
{
    void Run();

    void Swim();

    void Fly();

    IState SetShape();
}

具体的状态看起来像这样:

public class SpiderManState : IState
{
    public void Fly()
    {
        Console.WriteLine("Spiderman is flying");
    }

    public void Run()
    {
        Console.WriteLine("Spiderman is running");
    }

    public void Swim()
    {
        Console.WriteLine("Spiderman is swimming");
    }

    public IState SetShape()
    {
        return new IronManState();
    }
}

而IronManState看起来会像这样:

public class IronManState : IState
{
    public void Fly()
    {
        Console.WriteLine("IronMan is flying");
    }

    public void Run()
    {
        Console.WriteLine("IronMan is running");
    }

    public void Swim()
    {
        Console.WriteLine("IronMan is swimming");
    }

    public IState SetShape()
    {
        return new SpiderManState();
    }
}

通过点击 Hero 类的按钮 ChangeShape(),您将能够将英雄的 State 从例如 SpiderMan 改变为 IronMan
因此,上下文(Hero)的状态取决于并可以通过其按钮 ChangeShape 进行更改。这可以发生多次。
有很大的可能性您想要更改上下文的状态。 State 模式也可以被视为替换类中许多 if - else 语句的替代方案。

2

这个区别在http://c2.com/cgi/wiki?StrategyPattern上进行了讨论。我使用策略模式允许在整体框架内选择不同的算法来分析数据,通过这种方式,你可以添加算法而不必改变整体框架及其逻辑。

一个典型的例子是,你可能有一个优化函数的框架,该框架设置数据和参数。策略模式允许你选择算法,例如最陡下降法、共轭梯度法、BFGS等,而不会改变框架本身。


2

这两种模式都用于改变对象的行为。

按照设计,状态模式对象只有一个状态,对象的行为基于实现的单个状态(类)及其子类。

相比之下,策略模式没有单一状态,对象的行为取决于不同策略对象的实现。


1
"'策略'只是一种算法,您可以根据需要在不同情况下进行更改,并且它会为您处理某些内容。例如,您可以选择如何压缩文件 - zip或rar...通过一种方法。

但是'状态'可以改变所有对象的行为,当它发生变化时, 甚至它可以改变其他领域...这就是为什么它具有对其所有者的引用。您应该注意,更改对象字段会完全改变对象行为。 例如,当您将obj中的State0更改为State1时,您将一个整数更改为10..因此,当我们调用obj.f0()执行某些计算并使用该整数时,它会影响结果。

"

1
当您有一个可以分为2个任务的项目时:
任务1:您可以使用两种不同的算法之一来完成:alg1,alg2
任务2:您可以使用三种不同的算法之一来完成:alg3,alg4,alg5
alg1和alg2是可互换的;alg3,alg4和alg5也是可互换的。
选择在任务1和任务2中执行哪种算法取决于状态:
状态1:您需要在任务1中使用alg1,在任务2中使用alg3
状态2:您需要在任务1中使用alg2,在任务2中使用alg5
您的上下文可以从状态1更改为状态2。然后您的任务将由alg2和alg5完成,而不是alg1和alg3。
您可以为任务1或任务2添加更多可互换的算法。这就是策略模式。
您可以拥有更多状态,其中包含任务1和任务2中不同组合的算法。状态模式允许您从一个状态切换到另一个状态并执行不同的算法组合。

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