设计模式(二): 策略模式

概要:

策略模式(Strategy):他定义了算法家族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化,不会影响到算法的客户端。

当有一组算法完成的都是相同的工作,只是实现不同,以相同的方式调用所有的算法。在这种情况下可以使用策略模式,可减少各类算法类与使用算法类之间的耦合。

问题初探:

这边就以简单的数字加减举例。

 1 static class Calculate
 2 {
 3     private static string Add = "+";
 4     private static string Subtract = "-";
 5 
 6     public static double Calac(double a, double b, string symbol)
 7     {
 8         double result = 0.0;
 9         if (symbol == Add)
10         {
11             result = a + b;
12         } else if (symbol == Subtract)
13         {
14             result = a - b;
15         }
16 
17         return result;
18     }
19 }

 

这样写的化,在后期代码扩展*或者/的时候,就需要添加新的if 判断,代码臃肿且扩展性低。

如果使用策略模式,将各类运算归结到不同的策略中,会有很强的扩展性。那下面看下该模式。

模式讲解:

策略模式结构图:

组成:

1.抽象策略角色(Straetegy): 这是一个抽象类,通常情况下使用接口或抽像类去实现。

2.具体策略角色(ConcreteStrategyA....): 包装了具体的算法和行为。也就是实现 抽象策略角色 接口的实现类。

3.环境角色(Context): 持有一个抽象角色的引用,给客户端调用。

结构图的实现:

Strategy 类,定义所有支持的算法和公共接口:

1 abstract class Strategy
2 {
3     // 算法方法
4     public abstract void Algorithmlnterface();
5 }

ConcreteStrategy,封装了具体的算法或行为,继承于Strategy.

 1 // 具体算法A
 2 class ConcreteStrategyA : Strategy
 3 {
 4     public override void Algorithmlnterface()
 5     {
 6         Console.WriteLine("算法A 的实现");
 7     }
 8 }
 9 
10 // 具体算法B
11 class ConcreteStrategyB : Strategy
12 {
13     public override void Algorithmlnterface()
14     {
15         Console.WriteLine("算法B 的实现");
16     }
17 }
18 
19 // 具体算法 C
20 class ConcreteStrategyC : Strategy
21 {
22     public override void Algorithmlnterface()
23     {
24         Console.WriteLine("算法C 的实现");
25     }
26 }

 Context,用一个ConcreteStrategy来配置,维护一个对Strategy对象的引用。

// 上下文
class Context
{
    Strategy strategy;
    // 初始化时,传入具体的策略对象
    public Context(Strategy strategy)
    {
        this.strategy = strategy;
    }
    // 上下文
    public void ContextInterface()
    {
        // 根据具体的策略对象,调用其算法的方法
        strategy.Algorithmlnterface();
    }
}

客户端代码

 1 static void Main(string[] args)
 2 {
 3     Context context;
 4 
 5     // 由于实例化不同的策略,所以最终在调用 context.ContextInterface(); 时,所获得的结果就不尽相同
 6     context = new Context(new ConcreteStrategyA());
 7     context.ContextInterface();
 8 
 9     context = new Context(new ConcreteStrategyB());
10     context.ContextInterface();
11 
12     context = new Context(new ConcreteStrategyC());
13     context.ContextInterface();
14 }

 问题改进:

 了解了策略模式,那改写一下上面的加减算法吧。

 1 // 定义抽象类接口
 2 public interface ICalculator
 3 {
 4     double Calc(double a, double b);
 5 }
 6 
 7 // 加减的实现
 8 public class Add : ICalculator
 9 {
10     public double Calc(double a, double b)
11     {
12         return a + b;
13     }
14 }
15 
16 public class Sub : ICalculator
17 {
18     public double Calc(double a, double b)
19     {
20         return a - b;
21     }
22 }
23 
24 // 上下文
25 public class ClcContext
26 {
27     private ICalculator mcalculator;
28 
29     public ClcContext(ICalculator calculator)
30     {
31         this.mcalculator = calculator;
32     }
33 
34     public double Clc(double a, double b)
35     {
36         return mcalculator.Calc(a, b);
37     }
38 }

 

客户端这样调用就可以了

1 static void Main(string[] args)
2 {
3     // 客户端调用
4     ICalculator icalculator = new Add();
5     ClcContext context = new ClcContext(icalculator);
6     double result = context.Clc(1,2);
7 }

 

如果后期在加乘法的扩展就会方便很多,添加类继承即可。

特点:

  • 抽象类中可以定义一系列可供重复使用的算法或行为,继承有助于取出这些算法中的公共功能。
  • 简化了单元测试,每个算法有自己的类,可以通过自己的接口单独测试。
  • 当不同的行为堆砌在一个类中,就需要使用条件语句来选择合适的方法,当使用策略模式时,可消除条件判断。
  • 策略模式就是用来封装算法,但在实现中,几乎可以用他封装任何类型的规则,只要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化。

策略模式还可以于 简单过程模式 结合,使代码的耦合度更加降低。

posted @ 2019-08-06 21:33  十六号街  阅读(132)  评论(0编辑  收藏  举报