设计模式学习之路——Strategy 策略模式
1. 意图
定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
2. 动机
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?
如果一个程序需要一种特定的服务或功能,而且该程序有多种实现该功能的方式,此时适合于使用策略模式。程序可根据运算效率或用户选项在这些算法之间选择。程序中可以有任意数量的策略,可以添加策略,也可以在任何时候修改策略。
3. 结构
4. 代码实现
类关系图如下
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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | using System.Collections.Generic; using System.Text; namespace Strategy { class Program { static void Main( string [] args) { Helicopter h = new Helicopter(); Console.WriteLine( "" ); Fighter f = new Fighter(); Console.ReadKey(); } } public interface FlyBehavior { void fly(); } public class SuperSonicFly : FlyBehavior { public void fly() { Console.WriteLine( "超音速飞行!" ); } } public class SubSonicFly : FlyBehavior { public void fly() { Console.WriteLine( "亚音速飞行!" ); } } public interface TakeOffBehavior { void takeOff(); } public class VerticalTakeOff : TakeOffBehavior { public void takeOff() { Console.WriteLine( "垂直起飞!" ); } } public class LongDistanceTakeOff : TakeOffBehavior { public void takeOff() { Console.WriteLine( "长距离起飞!" ); } } public abstract class AirCraft { protected FlyBehavior flyBehavior; protected TakeOffBehavior takeOffBehavior; public void fly() { flyBehavior.fly(); } public void takeOff() { takeOffBehavior.takeOff(); } } public class Helicopter : AirCraft { public Helicopter() { flyBehavior = new SubSonicFly(); takeOffBehavior = new VerticalTakeOff(); Console.WriteLine( "直升飞机" ); fly(); takeOff(); } } public class Fighter : AirCraft { public Fighter() { flyBehavior = new SuperSonicFly(); takeOffBehavior = new LongDistanceTakeOff(); Console.WriteLine( "战斗机" ); fly(); takeOff(); } } } |
5. .NET体系架构中的Strategy模式
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 72 73 74 75 76 77 78 79 80 | using System; using System.Collections; public class SamplesArrayList { public class myReverserClass : IComparer { // Calls CaseInsensitiveComparer.Compare with the parameters reversed. int IComparer.Compare( Object x, Object y ) { return ( ( new CaseInsensitiveComparer()).Compare( y, x ) ); } } public static void Main() { // Creates and initializes a new ArrayList. ArrayList myAL = new ArrayList(); myAL.Add( "The" ); myAL.Add( "quick" ); myAL.Add( "brown" ); myAL.Add( "fox" ); myAL.Add( "jumps" ); myAL.Add( "over" ); myAL.Add( "the" ); myAL.Add( "lazy" ); myAL.Add( "dog" ); // Displays the values of the ArrayList. Console.WriteLine( "The ArrayList initially contains the following values:" ); PrintIndexAndValues( myAL ); // Sorts the values of the ArrayList using the default comparer. myAL.Sort(); Console.WriteLine( "After sorting with the default comparer:" ); PrintIndexAndValues( myAL ); // Sorts the values of the ArrayList using the reverse case-insensitive comparer. IComparer myComparer = new myReverserClass(); myAL.Sort( myComparer ); Console.WriteLine( "After sorting with the reverse case-insensitive comparer:" ); PrintIndexAndValues( myAL ); } public static void PrintIndexAndValues( IEnumerable myList ) { int i = 0; foreach ( Object obj in myList ) Console.WriteLine( "\t[{0}]:\t{1}" , i++, obj ); Console.WriteLine(); } } /* This code produces the following output. The ArrayList initially contains the following values: [0]: The [1]: quick [2]: brown [3]: fox [4]: jumps [5]: over [6]: the [7]: lazy [8]: dog After sorting with the default comparer: [0]: brown [1]: dog [2]: fox [3]: jumps [4]: lazy [5]: over [6]: quick [7]: the [8]: The After sorting with the reverse case-insensitive comparer: [0]: the [1]: The [2]: quick [3]: over [4]: lazy [5]: jumps [6]: fox [7]: dog [8]: brown */ |
6 Strategy模式的几个要点
1. Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。所谓封装算法,支持算法的变化。
2. Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
3. 与State类似,如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· dotnet 源代码生成器分析器入门
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· Vite CVE-2025-30208 安全漏洞
· 《HelloGitHub》第 108 期
· MQ 如何保证数据一致性?
· 一个基于 .NET 开源免费的异地组网和内网穿透工具