何时以及为什么要使用战略模式?

Use*_*er1 26 design-patterns strategy-pattern

何时使用战略模式

我看到像这样的客户端代码片段:


class StrategyExample {

    public static void main(String[] args) {

        Context context;

        // Three contexts following different strategies
        context = new Context(new ConcreteStrategyAdd());
        int resultA = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategySubtract());
        int resultB = context.executeStrategy(3,4);

        context = new Context(new ConcreteStrategyMultiply());
        int resultC = context.executeStrategy(3,4);

    }

}

看起来你可以将它重构为:


class StrategyExample {

    public static void main(String[] args) {
         // Three contexts following different strategies
        int resultA =new ConcreteStrategyAdd().execute(3,4);
        int resultB =new ConcreteStrategySubtract().execute(3,4);
        int resultC =new ConcreteStrategyMultiply().execute(3,4);
    }

}

第一部分代码直接来自维基百科页面.一个很大的区别是上下文消失了,但无论如何它都没有在示例中做任何事情.也许某人有一个更好的例子,其中策略是有道理的 我通常喜欢设计模式,但这个似乎增加了复杂性而没有增加实用性.

Ten*_*she 58

像这样的玩具示例的问题在于,通常很容易忽略这一点.在这种情况下,代码确实可以像您所示的那样实现.在策略模式中,主要价值在于能够针对不同情况切换出不同的实现.

您拥有的示例仅说明模式中的对象以及它们之间的交互.想象一下,你有一个组件可以为网站呈现图形,具体取决于它是真正的网络浏览器还是另一端的智能手机,你会有一些代码可以检测创建的​​浏览器类型并将策略设置为另一个可以在一些不需要复制的复杂代码中使用策略对象的组件,并且可以在两种情况下完成工作,将图形的实际绘制细节留给适当的策略对象:

interface GraphStrategy {
    Image renderGraph(Data graphData);
}

class BigGraphStrategy implements GraphStrategy {
    ...
}

class SmallGraphStrategy implements GraphStrategy {
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后在其他一些代码中:

GraphStrategy graphStrategy;

if (phoneBrowser == true) { 
    graphStrategy = new SmallGraphStrategy();
} else {
    graphStrategy = new BigGraphStrategy();
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用其余的应用程序代码,graphStrategy.renderGraph()而无需知道是否正在执行完整或小型图像渲染.

  • It bothers me that its called the strategy pattern, when the strategy of choosing the correct class is in the switch statement. 这更像是“界面策略”,因为它实际上只是界面的练习。你懂!?很好的例子。 (2认同)

Dou*_* T. 8

想到的领域:

  • 资源分配器.在手动资源管理中,这可能会最大限度地缩短资源分配所需的时间,或最大限度地减少碎片.这里的每个策略都有一个"Allocate"方法,该方法具有相同的界面,用户根据他们试图优化的内容决定使用哪种策略.
  • 一种连接和发送网络数据的方法.也许在某些情况下,您更愿意连接并发送UDP数据报,可能在其他情况下,其中性能不是您使用TCP/IP发送的因素.
  • 数据格式化/序列化策略.允许代码决定是使用Json还是使用Xml序列化对象.也许一个用于机器,另一个用于人类可读的情况.两种策略都有一个"序列化"方法,它接受一个对象.每个序列化不同.

主题是关于是否以某种方式做某事的决定取决于情境因素,您或您的代码将根据情况选择正确的策略.

现在为什么这比以下更有用:

void DoIt()
{
    if (... situation1...)
    {
       DoA()
    }
    else
    {
       DoB();
    }
}
Run Code Online (Sandbox Code Playgroud)

原因有时你只想做出一次决定而忘掉它.策略模式的另一个重要主题是,您可以将有关使用哪种策略的决策与需要执行策略的代码分离.

DoItStrategy MakeDoItStrategy()
{
     if (... situation1...)
     {
           return new DoItStrategyA();
     }
     else
     {
           return new DoItStrategyB();
     }
}
Run Code Online (Sandbox Code Playgroud)

在最后一个示例中,您可以只存储策略,将其作为另一个实现策略接口的对象传递.对于执行策略的人,他们只是有办法执行操作.他们不知道内部工作是什么,只是界面会满足.策略的用户不应该知道我们做出决定的原因.他们只需要做一个动作.我们做出一次决定并将策略传递给使用该策略的类.

例如,考虑我们基于给定的网络配置做出程序范围的决定,以使用UDP连接和发送数据到远程主机的情况.我们可以预先创建UDP策略并将其传递给需要发送网络数据的每个人,而不是网络接口的每个用户需要知道做出决策的逻辑(上面的"DoIt"功能).然后,该策略实现具有相同最终结果的简单接口 - 数据从A到B.