软件设计模式之策略模式(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杵在那,里面还有无数行实现,看着头都大。

posted @   壹-ZL  阅读(271)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示