策略模式

最近一直在学习设计模式,参考资料主要是程杰老师的大化设计模式,这本书真的很好,通俗易懂,道理深刻,适合设计模式的初学者去学习。

今天让我们认识一种新的设计模式——策略模式

策略模式的定义是这样的,它定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。

下面让我们来看看策略模式的结构图:

策略模式

Strategy—抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
ConcreteStategy—具体策略角色:包装了相关的算法和行为。
Context—环境角色:持有一个策略类的引用,最终给客户端调用。
下面让我们引入一个例子来说明问题:
例子还是上一篇简单工厂模式里的四则计算器,用简单工厂模式实现这个例子已经很好了,但为了让我们对策略模式有一个简单的认识我将对代码进行改变来以不同的方法实现相同的功能(没有看简单工厂模式的可以看一下以增强对这个例子的理解)
首先四则运算即是加,减,乘,除。同时也可以看做四个算法,我们现在要进行计算就面临着选择哪个算法的问题,所以就可以专门写一个类对“选择哪个算法”进行封装(相当于Context),同时也要定义一个“算法”类的父类(相当于Strategy),然后就是具体的算法类了(相当于ConcreteStrategy)
下面让我们来看看具体的C#代码:
namespace 策略模式之计算器
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            cmbSym.Items.AddRange(new object[]{"+","-","*","/"});
        }

        private void btnEqual_Click(object sender, EventArgs e)
        {
            CashContext cashContext=null;
            switch (cmbSym.SelectedItem.ToString())
            {
                case "+":
                    cashContext = new CashContext(new Add());
                    break;
                case "-":
                    cashContext = new CashContext(new Sub());
                    break;
                case "*":
                    cashContext = new CashContext(new Mul());
                    break;
                case "/":
                    cashContext = new CashContext(new Div());
                    break;
            }
            double number1 = Convert.ToDouble(txtNumber1.Text);
            double number2 = Convert.ToDouble(txtNumber2.Text);
            double result = cashContext.getResult(number1,number2);
            txtResult.Text = Convert.ToString(result);

        }
    }
    public abstract class opration
    {

        public abstract double GetResult(double NumberA,double NumberB);
       
    }
    class Add : opration
    {
        public override double GetResult(double NumberA,double NumberB)
        {
            double result = 0;
            result = NumberA + NumberB;
            return result;

        }
    }
    class Sub : opration
    {
        public override double GetResult(double NumberA,double NumberB)
        {
            double result = 0;
            result = NumberA - NumberB;
            return result;
        }
    }
    class Mul : opration
    {
        public override double GetResult(double NumberA,double NumberB)
        {
            double result = 0;
            result = NumberA * NumberB;
            return result;
        }
    }
    class Div : opration
    {
        public override double GetResult(double NumberA,double NumberB)
        {
            double result = 0;
            if (NumberB == 0)
            {
                throw new Exception("除数不能为零");
            }
            result = NumberA / NumberB;
            return result;
        }
    }
    class CashContext
    {
        opration op;
        public CashContext(opration op)
        {
            this.op = op;
        }
        public double getResult(double NumberA,double NumberB)
        {
            return op.GetResult(NumberA, NumberB);
        }
    }
}

当你看完这段代码的时候肯定会说这个例子在简单工厂模式中实现的不是挺好的吗,为什么又用策略模式来实现,而且这两个模式之间到底有什么不同呢?

下面是我自己总结的几点简单工厂模式和策略模式各自的特点:

1、在简单工厂模式中客户端只需传递相应的条件就能得到想要的对象,然后通过这个对象实现算法的操作(根据条件得到对象,利用对象调用方法)

2、在策略模式中,使用时必须首先创建一个想使用的具体算法的类对象,然后将该对象作为参数传入CashContext类中,通过这个参数对象调用自己的方法来实现(使用着自己决定使用哪个对象)

两者最大的区别就是:简单工厂模式如果增加了新类,那么工厂也要随之动动,在策略模式中,如果增加一个新类,Context类中不用改动,但客户端代码需要改动

在简单工厂中的客户端,客户需要认识两个类即工厂类和各算法类的基类,而在策略模式中客户只需认识一个类CashContext就可以了,所以这也进一步降低了耦合度。

在具体的系统中常常将两者结合使用