设计模式-策略者模式

一、定义

    策略模式是针对一组算法,将每个算法封装到具有公共接口的独立的类中,从而使它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。

二、UML类图

image

三、例子展示

namespace 策略者模式
{
    public interface ITaxStrategy
    {
        double GetTax(double money);
    }

    public class PersnalStrategy : ITaxStrategy
    {
        public double GetTax(double money)
        {
            return money * 0.1;
        }
    }

    public class EnterpriseTaxStrategy : ITaxStrategy
    {
        public double GetTax(double money)
        {
            return (money - 4000) > 0 ? (money - 4000) * 0.045 : 0.0;
        }
    }

    public class TaxContext
    {
        private ITaxStrategy _strategy;

        public TaxContext(ITaxStrategy taxStrategy)
        {
            _strategy = taxStrategy;
        }

        public double GetTax(double money)
        {
            return _strategy.GetTax(money);
        }
    }

    public class Client
    {
        public static void Process()
        {
            TaxContext taxContext = new TaxContext(new PersnalStrategy());
            double tax = taxContext.GetTax(10000);
            Console.WriteLine("个人所得税:"+tax);

             taxContext = new TaxContext(new EnterpriseTaxStrategy());
             tax = taxContext.GetTax(100000);
            Console.WriteLine("企业所得税:" + tax);

            // 与简单工厂模式一起,避免客户端既依赖于TaxContext,又依赖于具体策略者。这样客户端只需要知道TaxContext就可以了
            TaxContext2 taxContext2 = new TaxContext2("PersnalStrategy");
            double tax2 = taxContext2.GetTax(10000);
            Console.WriteLine("升级版 个人所得税:" + tax2);

            taxContext2 = new TaxContext2("EnterpriseTaxStrategy");
            tax2 = taxContext2.GetTax(100000);
            Console.WriteLine("升级版 企业所得税:" + tax2);
        }
    }

    public class TaxContext2
    {
        private ITaxStrategy _strategy;

        /// <summary>
        /// 简单工厂一起
        /// </summary>
        /// <param name="taxType"></param>
        public TaxContext2(string taxType)
        {
            switch (taxType)
            {
                case "PersnalStrategy":
                    _strategy = new PersnalStrategy();
                    break;
                case "EnterpriseTaxStrategy":
                    _strategy = new EnterpriseTaxStrategy();
                    break;
                default:
                    break;
            }
        }

        public double GetTax(double money)
        {
            return _strategy.GetTax(money);
        }
    }
}
View Code

四、项目中实际用到

我们是做在线练习系统。其中有个功能模块,判断试题的对错。对于不同的题型:单选、多选、判断、填空、解答,判断对错的算法不同,但是本质都是要得到这道题是否正确。

首先我们可以抽象出一个得到对错的算法接口,即策略者类:

public interface IJudgeCorrect<TDoQuestion>
{
    bool DoJugeCorrect(TDoQuestion doQuestion);
} 
View Code

接下来写各种不同题型得到对错的类,具体策略者类:

// 判断选择题的策略者

public class JudgeChoiceQuestionCorrect : IJudgeCorrect<DoQuestion>
{
    public bool DoJugeCorrect(DoQuestion doQuestion)
    {
        if (string.IsNullOrEmpty(doQuestion.Answer))
        {
            return false;
        }

        // 对Answer按照abcd的顺序排序,有可能从前台传来的数据不对
        if (doQuestion.Answer.Length > 1)
        {
            var answerarray = doQuestion.Answer.ToCharArray().OrderBy(p => p).ToArray();
            doQuestion.Answer = new string(answerarray);
        }

        return doQuestion.Question.Answer.Trim() == doQuestion.Answer.Trim();
    }
}

 

// 判断题策略者类

public class JudgeTrueFalseQuestionCorrect : IJudgeCorrect<DoQuestion>
{
    public bool DoJugeCorrect(DoQuestion doQuestion)
    {

        if (string.IsNullOrEmpty(doQuestion.Answer))
        {
            return false;
        }

        return doQuestion.Question.Answer.Trim() == doQuestion.Answer.Trim();
    }
} 
View Code

其他题型不再一一列举。

和简单工厂联合,得到具体策略者。

public class JudgeCorrectFactory : IJudgeCorrectFactory<Question,DoQuestion>
    {
        private  Dictionary<QuestionMode, IJudgeCorrect<DoQuestion>> _factoties = new Dictionary<QuestionMode, IJudgeCorrect<DoQuestion>>();

        public  IJudgeCorrect<DoQuestion> CreateJudgeCorrect(Question question)
        {
            IJudgeCorrect<DoQuestion> jugeCorrect = null ;

            switch (question.QuestionMode)
            {
                case QuestionMode.SingleChoice:
                case QuestionMode.DoubleChoice:
                case QuestionMode.MultipleChoice:
                    if (_factoties.Keys.Contains(QuestionMode.SingleChoice))
                    {
                        jugeCorrect = _factoties[QuestionMode.SingleChoice];
                    }
                    else
                    {
                        jugeCorrect = new JudgeChoiceQuestionCorrect();
                        _factoties.Add(QuestionMode.SingleChoice, jugeCorrect);
                    }                  
                    break;
                case QuestionMode.TrueFalse:
                    if (_factoties.Keys.Contains(QuestionMode.TrueFalse))
                    {
                        jugeCorrect = _factoties[QuestionMode.TrueFalse];
                    }
                    else
                    {
                        jugeCorrect = new JudgeTrueFalseQuestionCorrect();
                        _factoties.Add(QuestionMode.TrueFalse, jugeCorrect);
                    }
                    break;
                case QuestionMode.FillBlank:
                    if (_factoties.Keys.Contains(QuestionMode.FillBlank))
                    {
                        jugeCorrect = _factoties[QuestionMode.FillBlank];
                    }
                    else
                    {
                        jugeCorrect = new JudgeFillBlankQuestionCorrect();
                        _factoties.Add(QuestionMode.FillBlank, jugeCorrect);
                    }
                    break;
                case QuestionMode.Discuss:
                    if (_factoties.Keys.Contains(QuestionMode.Discuss))
                    {
                        jugeCorrect = _factoties[QuestionMode.Discuss];
                    }
                    else
                    {
                        jugeCorrect = new JudgeDiscussQuestionCorrect();
                        _factoties.Add(QuestionMode.Discuss, jugeCorrect);
                    }
                    break;
                case QuestionMode.Complex:
                    if (_factoties.Keys.Contains(QuestionMode.Complex))
                    {
                        jugeCorrect = _factoties[QuestionMode.Complex];
                    }
                    else
                    {
                        jugeCorrect = new JudgeComplexQuestionCorrect(this);
                        _factoties.Add(QuestionMode.Complex, jugeCorrect);
                    }
                    break;
                default:
                    throw new Exception("获取判断试卷参数错误!");
            }

            return jugeCorrect;
        }
    }
View Code

具体应用上下文中,通过构造函数传入工厂:

public SubmitStudyInfo(TDbContext dbContext, IJudgeCorrectFactory<Question, DoQuestion> jugeCorrectFactory)
       {
           _jugeCorrectFactory = jugeCorrectFactory;
           _dbContext = dbContext;
       } 
View Code

五、总结

策略者模式主要是对算法的封装,把一系列算法封装到策略者类中,从而可以是不同的策略类自由切换而且避免了在代码中写很多if 或者switch。

原文地址:https://www.cnblogs.com/zh1990/p/6118280.html