软件设计模式之策略模式(Strategy)
策略模式
描述
它定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化不会影响到使用算法的客户。
优点
策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合。
策略模式的Strategy类为Context定义了很多可重用的算法,继承可以让你更好地析取出算法中的公共功能,同时简化了单元测试,因为每个算法都是单独的类,都可以通过自己单独的接口进行测试。
简而言之呢就是策略封装了算法会有的变化
实现
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 | /* 策略模式 */ /// <summary> /// 策略模式抽象算法类 /// </summary> abstract class Strategy { public abstract void AlgorithmInterface(); } /// <summary> /// 策略模式实现类A /// </summary> class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法A实现" ); } } /// <summary> /// 策略模式实现类B /// </summary> class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法B实现" ); } } /// <summary> /// 策略模式实现类C /// </summary> class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法C实现" ); } } /// <summary> /// 上下文接口 /// </summary> class Context { Strategy _strategy; /// <summary> /// 初始化时传入策略对象 /// </summary> /// <param name="strategy"></param> public Context(Strategy strategy) { _strategy = strategy; } /// <summary> /// 调用算法 /// </summary> public void ContextInterface() { _strategy.AlgorithmInterface(); } } |
与简单工厂差别
工厂模式是创建型模式,适应对象的变化。
策略模式是行为性模式,适应行为的变化。
策略模式、简单工厂适用场景
我认为工厂模式适合的场景是不复杂的,比较具体的,比如文具:铅笔、尺子、橡皮;
策略模式则是适用于算法的,比如商场折扣:买200反20,买300反30;
简单工厂+策略模式的使用
策略模式封装了算法,但是实际使用中不可避免的会用到switch,策略模式+简单工厂的模式就可以将条件判断封装起来,避免了在界面层做过多的条件判断。
操作类实现:还是使用策略模式的实现
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 | /// <summary> /// 策略模式抽象算法类 /// </summary> abstract class Strategy { public abstract void AlgorithmInterface(); } /// <summary> /// 策略模式实现类A /// </summary> class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法A实现" ); } } /// <summary> /// 策略模式实现类B /// </summary> class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法B实现" ); } } |
然后上下文跟策略模式有所不同,上下文加入简单工厂的思想
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 | /// <summary> /// 简单工厂+策略模式 /// </summary> class FactoryContext { Strategy _strategy; /// <summary> /// 工厂生成 /// </summary> /// <param name="type"></param> public FactoryContext( string type) { switch (type) { case "A" : _strategy = new ConcreteStrategyA(); break ; case "B" : _strategy = new ConcreteStrategyB(); break ; case "C" : _strategy = new ConcreteStrategyC(); break ; } } /// <summary> /// 调用算法 /// </summary> public void ContextInterface() { _strategy.AlgorithmInterface(); } } |
反射
策略模式+简单工厂,也只是把条件判断封装了起来而已,那可不可能不用switch了呢?可以,那就需要用到反射,“反射,反射,程序员的快乐”
实现
首先我们编写标识类,标识类使用Attribute类来做我觉得会好一点
1 2 3 4 5 6 7 8 | public class ReflectAttribute : Attribute { public string Tag { get ; set ; } public ReflectAttribute( string tag) { Tag = tag; } } |
然后我们给实现类打上标识
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 | /// <summary> /// 策略模式实现类A /// </summary> [ReflectAttribute( "A" )] class ConcreteStrategyA : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法A实现" ); } } /// <summary> /// 策略模式实现类B /// </summary> [ReflectAttribute( "B" )] class ConcreteStrategyB : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法B实现" ); } } /// <summary> /// 策略模式实现类C /// </summary> [ReflectAttribute( "C" )] class ConcreteStrategyC : Strategy { public override void AlgorithmInterface() { Console.WriteLine( "算法C实现" ); } } |
最后改造上下文
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 | /// <summary> /// 反射实现工厂+策略模式 /// </summary> class ReflectContext { Strategy _strategy; public ReflectContext( string type) { Type abjType = typeof (Strategy); Assembly assem = abjType.Assembly; foreach (Type item in assem.GetTypes()) { if (item.IsClass && !item.IsAbstract && item.IsSubclassOf(abjType)) { if (item.GetCustomAttribute<ReflectAttribute>().Tag == type) { _strategy = Activator.CreateInstance(item) as Strategy; } } } } public void ContextInterface() { _strategy.AlgorithmInterface(); } } |
使用反射来优化策略模式就完成了。同时反射这种使用也可以用在需要写很多case的情况下,日常工作中经常会遇到,那么我觉得可以用一个类去封装switch中case的执行语句,然后每个执行方法打上标识,然后用反射去找到每个方法,这样代码看起来会舒服很多,而不是几百个case杵在那,里面还有无数行实现,看着头都大。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战