企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持知识库和私有化部署方案 广告
# 策略模式(Strategy) ## **策略模式的定义** 策略(Strategy)模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。 **优点** 1. 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句。 2. 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。 3. 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。 4. 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。 5. 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。 **缺点** 1. 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。 2. 策略模式造成很多的策略类。 > 策略模式是准备一组算法,并将这组算法封装到一系列的策略类里面,作为一个抽象策略类的子类。策略模式的重心不是如何实现算法,而是如何组织这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性,现在我们来分析其基本结构和实现方法。 ## **策略模式的应用场景** 策略模式在很多地方用到,如[Java](http://c.biancheng.net/java/)SE 中的容器布局管理就是一个典型的实例,Java SE 中的每个容器都存在多种布局供用户选择。在程序设计中,通常在以下几种情况中使用策略模式较多。 1. 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中。 2. 一个类定义了多种行为,并且这些行为在这个类的操作中以多个条件语句的形式出现,可将每个条件分支移入它们各自的策略类中以代替这些条件语句。 3. 系统中各算法彼此完全独立,且要求对客户隐藏具体算法的实现细节时。 4. 系统要求使用算法的客户不应该知道其操作的数据时,可使用策略模式来隐藏与算法相关的[数据结构](http://c.biancheng.net/data_structure/)。 5. 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。 应用场景总结:用于对象间的替换 ## **模式的结构** 1. 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。 2. 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。 3. 环境(Context)类:持有一个策略类的引用,最终给客户端调用。 ![](https://img.kancloud.cn/0a/e3/0ae344539f86258b9c91a07a8b69568b_716x325.png) ``` <pre class="calibre10">``` <span class="token">//抽象策略类</span> interface <span class="token4">Strategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//策略方法</span> <span class="token3">}</span> <span class="token">//具体策略类A</span> class <span class="token4">ConcreteStrategyA</span> implements <span class="token4">Strategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">print_r</span><span class="token3">(</span><span class="token2">"具体策略A的策略方法被访问!"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//具体策略类B</span> class <span class="token4">ConcreteStrategyB</span> implements <span class="token4">Strategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">print_r</span><span class="token3">(</span><span class="token2">"具体策略B的策略方法被访问!"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//环境类</span> class <span class="token4">Context</span> <span class="token3">{</span> private $strategy<span class="token3">;</span> <span class="token">//Strategy</span> <span class="token">/** * 获取策略类 * @return Strategy [description] */</span> public <span class="token5">function</span> <span class="token4">getStrategy</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>strategy<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">setStrategy</span><span class="token3">(</span>Strategy $strategy<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>strategy <span class="token1">=</span> $strategy<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>strategy<span class="token1">-</span><span class="token1">></span><span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">StrategyPattern</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">main</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $context <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Context</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $strategy <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ConcreteStrategyA</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $context<span class="token1">-</span><span class="token1">></span><span class="token4">setStrategy</span><span class="token3">(</span>$strategy<span class="token3">)</span><span class="token3">;</span> $context<span class="token1">-</span><span class="token1">></span><span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token4">print_r</span><span class="token3">(</span><span class="token2">"<br>-----------------<br>"</span><span class="token3">)</span><span class="token3">;</span> $strategy <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ConcreteStrategyB</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $context<span class="token1">-</span><span class="token1">></span><span class="token4">setStrategy</span><span class="token3">(</span>$strategy<span class="token3">)</span><span class="token3">;</span> $context<span class="token1">-</span><span class="token1">></span><span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> 结果: 具体策略A的策略方法被访问! <span class="token1">--</span><span class="token1">--</span><span class="token1">--</span><span class="token1">--</span><span class="token1">--</span><span class="token1">--</span><span class="token1">--</span><span class="token1">--</span><span class="token1">-</span> 具体策略B的策略方法被访问! ``` ``` 例子: ![](https://img.kancloud.cn/65/c8/65c85176e948fa134ad8bddf2fcf9402_703x287.png) ``` <pre class="calibre10">``` interface <span class="token4">TripMode</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> class <span class="token4">ByTrain</span> implements <span class="token4">TripMode</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"乘坐火车出行"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">ByCar</span> implements <span class="token4">TripMode</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"坐汽车出行"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">SelfDrive</span> implements <span class="token4">TripMode</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> echo <span class="token2">"自驾车出行"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">WyTour</span> <span class="token3">{</span> private $tm<span class="token3">;</span> public <span class="token5">function</span> <span class="token4">setTripMode</span><span class="token3">(</span>TripMode $tm<span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>tm <span class="token1">=</span> $tm<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">getTripMode</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token5">return</span> $this<span class="token1">-</span><span class="token1">></span>tm<span class="token3">;</span> <span class="token3">}</span> public <span class="token5">function</span> <span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> $this<span class="token1">-</span><span class="token1">></span>tm<span class="token1">-</span><span class="token1">></span><span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> $byCar <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ByCar</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $byTrain <span class="token1">=</span> <span class="token5">new</span> <span class="token4">ByTrain</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $selfDrive <span class="token1">=</span> <span class="token5">new</span> <span class="token4">SelfDrive</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $wt <span class="token1">=</span> <span class="token5">new</span> <span class="token4">WyTour</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $wt<span class="token1">-</span><span class="token1">></span><span class="token4">setTripMode</span><span class="token3">(</span>$byCar<span class="token3">)</span><span class="token3">;</span> $wt<span class="token1">-</span><span class="token1">></span><span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $wt<span class="token1">-</span><span class="token1">></span><span class="token4">setTripMode</span><span class="token3">(</span>$byTrain<span class="token3">)</span><span class="token3">;</span> $wt<span class="token1">-</span><span class="token1">></span><span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $wt<span class="token1">-</span><span class="token1">></span><span class="token4">setTripMode</span><span class="token3">(</span>$selfDrive<span class="token3">)</span><span class="token3">;</span> $wt<span class="token1">-</span><span class="token1">></span><span class="token4">getOut</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` 例子: ``` <pre class="calibre10">``` <span class="token">/** * 策略模式 Strategy * */</span> <span class="token5">function</span> <span class="token4">output</span><span class="token3">(</span>$string<span class="token3">)</span> <span class="token3">{</span> echo $string <span class="token3">.</span> <span class="token2">"n"</span><span class="token3">;</span> <span class="token3">}</span> <span class="token">//策略基类接口 </span> interface <span class="token4">IStrategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">OnTheWay</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> class <span class="token4">WalkStrategy</span> implements <span class="token4">IStrategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">OnTheWay</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">output</span><span class="token3">(</span> <span class="token2">'在路上步行'</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">RideBickStrategy</span> implements <span class="token4">IStrategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">OnTheWay</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">output</span><span class="token3">(</span> <span class="token2">'在路上骑自行车'</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">CarStrategy</span> implements <span class="token4">IStrategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">OnTheWay</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">output</span><span class="token3">(</span> <span class="token2">'在路上开车'</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//选择策略类Context </span> class <span class="token4">Context</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">find</span><span class="token3">(</span>$strategy<span class="token3">)</span> <span class="token3">{</span> $strategy<span class="token1">-</span><span class="token1">></span><span class="token4">OnTheWay</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">Client</span> <span class="token3">{</span> public static <span class="token5">function</span> <span class="token4">test</span><span class="token3">(</span><span class="token3">)</span><span class="token3">{</span> $travel <span class="token1">=</span> <span class="token5">new</span> <span class="token4">Context</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> $travel<span class="token1">-</span><span class="token1">></span><span class="token4">find</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">WalkStrategy</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $travel<span class="token1">-</span><span class="token1">></span><span class="token4">find</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">RideBickStrategy</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> $travel<span class="token1">-</span><span class="token1">></span><span class="token4">find</span><span class="token3">(</span><span class="token5">new</span> <span class="token4">CarStrategy</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> Client<span class="token3">:</span><span class="token3">:</span><span class="token4">test</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> ``` ``` ## 策略模式的扩展 在一个使用策略模式的系统中,当存在的策略很多时,客户端管理所有策略算法将变得很复杂,如果在环境类中使用策略工厂模式来管理这些策略类将大大减少客户端的工作复杂度,其结构图如图 ![](https://img.kancloud.cn/a7/c3/a7c3f67460c5448c5be1e74b022ab167_800x304.png) ``` <pre class="calibre17">``` <span class="token">//抽象策略类</span> interface <span class="token4">Strategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token">//策略方法</span> <span class="token3">}</span> <span class="token">//具体策略类A</span> class <span class="token4">ConcreteStrategyA</span> implements <span class="token4">Strategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">print_r</span><span class="token3">(</span><span class="token2">"具体策略A的策略方法被访问!"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> <span class="token">//具体策略类B</span> class <span class="token4">ConcreteStrategyB</span> implements <span class="token4">Strategy</span> <span class="token3">{</span> public <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span> <span class="token3">{</span> <span class="token4">print_r</span><span class="token3">(</span><span class="token2">"具体策略B的策略方法被访问!"</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> class <span class="token4">StrategyFactory</span><span class="token3">{</span> static $strategys<span class="token1">=</span><span class="token4">array</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> public static <span class="token5">function</span> <span class="token4">put</span><span class="token3">(</span>string $key<span class="token3">,</span> Strategy $sy<span class="token3">)</span><span class="token3">{</span> StrategyFactory<span class="token3">:</span><span class="token3">:</span>$strategys<span class="token3">[</span>$key<span class="token3">]</span><span class="token1">=</span>$sy<span class="token3">;</span> <span class="token3">}</span> public static <span class="token5">function</span> <span class="token4">get</span><span class="token3">(</span>string $key<span class="token3">)</span><span class="token3">{</span> <span class="token5">return</span> StrategyFactory<span class="token3">:</span><span class="token3">:</span>$strategys<span class="token3">[</span>$key<span class="token3">]</span><span class="token3">;</span> <span class="token3">}</span> public static <span class="token5">function</span> <span class="token4">strategyMethod</span><span class="token3">(</span>$key<span class="token3">)</span><span class="token3">{</span> StrategyFactory<span class="token3">:</span><span class="token3">:</span>$strategys<span class="token3">[</span>$key<span class="token3">]</span><span class="token1">-</span><span class="token1">></span><span class="token4">strategyMethod</span><span class="token3">(</span><span class="token3">)</span><span class="token3">;</span> <span class="token3">}</span> <span class="token3">}</span> StrategyFactory<span class="token3">:</span><span class="token3">:</span><span class="token4">put</span><span class="token3">(</span><span class="token2">"a"</span><span class="token3">,</span> <span class="token5">new</span> <span class="token4">ConcreteStrategyA</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> StrategyFactory<span class="token3">:</span><span class="token3">:</span><span class="token4">put</span><span class="token3">(</span><span class="token2">"b"</span><span class="token3">,</span> <span class="token5">new</span> <span class="token4">ConcreteStrategyB</span><span class="token3">(</span><span class="token3">)</span><span class="token3">)</span><span class="token3">;</span> StrategyFactory<span class="token3">:</span><span class="token3">:</span><span class="token4">strategyMethod</span><span class="token3">(</span><span class="token2">"a"</span><span class="token3">)</span><span class="token3">;</span> ``` ```