• 策略模式


    策略模式

    一、策略模式简介

    定义:策略模式定义了一系列的算法,并将所有算法封装起来,而且它们之间可以相互替换,让算法独立于使用它的客户而独立变化。

    分析:算法之间可以相互替换,也就是说它们之间有共性,它们共性体现在策略接口的行为上,为了 让算法独立于使用它的客户而独立变化 这个句话,那么我们要让客户端依赖于策略接口。

    直白点说:就是客户只管他需要什么算法,得到对应的正确的计算结果就行。不用管内部是怎么实现或做到的。

    使用场景:

    1.同类型的问题,但不同的处理方式,仅仅是具体逻辑或行为上的差别。

    2.需要安全的封装多种同类型的操作时。

    3.出现同一抽象类有多个子类,而又需要使用 if-else 或者 switch-case 来选择具体子类时。

    废话不多说,我们看下实际例子:

    二、实际 Demo

    原需求:以面向对象的思想设计一个价格计算器。

    考虑过程:

    既然是价格计算器,那么我们界面上只需要让物品数量、价格。就可以直接计算出结果。代码略...

    需求变更1.0:计算器可以带上打折功能。

    既然是带打折功能,那么我们直接在上一个需求的基础上,添加多一个打折选项,计算过程再修改下,就能正常跑起来了。(注意,此时需求已经发生变化了,但我们还在修改原来的类,违反了单一职责、开闭原则。坏代码的味道出现了!!!)

    代码略....

    需求变更2.0:计算器还可以做满减活动,如满 200-20 的优惠。

    !!!

    问题出现了,如果我们还继续在上一个代码的基础上改,那么下次如果再一次出现新的需求,比如:又要可以满减,又可以打折,还有积分功能。请问,你怎么办?还在原代码改?继续改下去?这样难免会出现遗漏、逻辑出现错误,而且可能会出现,修复了一个 BUG 之后,另一个地方不小心被我们影响到了,导致出现一个新的 BUG 。

    那么,这时候,我们的 策略模式 就应该出场了。

    我们先进行一波分析:

    1.计算器的计算方法是变化的。

    2.计算方法有多种,也就是说策略是有多种。

    我们来实际写一个代码吧:

    首先,我们定义一个抽象的策略类:

            /// <summary>
            /// 抽象策略类
            /// </summary>
            public abstract class cacleStrategy
            {
                /// <summary>
                /// 取得最终的金额 的 抽象方法
                /// </summary>
                /// <param name="money">实际要计算的金额</param>
                /// <returns>计算结果金额</returns>
                public abstract double getResultMoney(double money);
            }

    接下来,我们来实现打折的算法:

            /// <summary>
            /// 打折计算 算法类
            /// </summary>
            public class discountedCacle : cacleStrategy
            {
                /// <summary>
                /// 折扣
                /// </summary>
                private double _discountedPercent { get; set; }
    
                /// <summary>
                /// 构造函数
                /// </summary>
                /// <param name="discountedPercent">折扣</param>
                public discountedCacle(double discountedPercent)
                {
                    _discountedPercent = discountedPercent;
                }
    
    
                /// <summary>
                /// 计算打折的结果
                /// </summary>
                /// <param name="money"></param>
                /// <returns></returns>
                public override double getResultMoney(double money)
                {
                    return money * _discountedPercent;
                }
            }

    接下来,我们实现满减的算法:

            /// <summary>
            /// 满减算法 类
            /// </summary>
            public class fullMinusCacle : cacleStrategy
            {
                /// <summary>
                /// 最少开始满减的金额
                /// </summary>
                private double _fullMinPrice { get; set; }
    
                /// <summary>
                /// 减多少钱
                /// </summary>
                private double _fullMinusPrice { get; set; }
    
                /// <summary>
                /// 构造函数
                /// </summary>
                /// <param name="fullMinPrice">最少开始满减的金额</param>
                /// <param name="fullMinusPrice">减多少钱</param>
                public fullMinusCacle(double fullMinPrice, double fullMinusPrice)
                {
                    _fullMinPrice = fullMinPrice;
                    _fullMinusPrice = fullMinusPrice;
                }
    
                /// <summary>
                /// 计算结果
                /// </summary>
                /// <param name="money"></param>
                /// <returns></returns>
                public override double getResultMoney(double money)
                {
                    if (money >= _fullMinPrice)
                    {
                        return money - _fullMinusPrice;
                    }
                    else
                    {
                        return money;
                    }
                }
    
            }

    现在我们有了抽象策略类,实际实现的策略类,那么,我们需要一个上下文对象来实例化这些东西:

            /// <summary>
            /// 策略上下文类
            /// </summary>
            public class CacleContext
            {
    
                private cacleStrategy _strategy;
    
    
                public CacleContext(cacleStrategy cacleStrategy)
                {
                    _strategy = cacleStrategy;
                }
    
                public double getResultMoney(double money) 
                {
                    return _strategy.getResultMoney(money);
                }
            }

    我们来测试下:

            static void CacleContextMain(string[] args)
            {
                double price=510;
                Console.WriteLine("1.满减功能:");
                cacleStrategy fullMoney = new fullMinusCacle(100, 20);
                double resultMoney= fullMoney.getResultMoney(price);
                Console.WriteLine("最终结果:"+resultMoney);
    
    
                Console.WriteLine("2.打折功能:");
                cacleStrategy discountMoney = new discountedCacle(0.9);
    
                resultMoney= discountMoney.getResultMoney(price);
                Console.WriteLine("最终结果:" + resultMoney);
    
    
                Console.Read();
            } 

    结果我就不写出来了,代码简单,跑一下就知道了。

    好了,这样,我们就实现了 策略模式,但!还记得我们上一次写的简单工厂么?不觉得这种写法很熟悉么?可以把我们的简单工厂和策略模式整合在一起。

    下面是 Demo :

            /// <summary>
            /// 策略工厂
            /// </summary>
            public class cacleFactory
            {
                private cacleStrategy _cacle;
                public cacleFactory(string type)
                {
                    switch (type)
                    {
                        case "full":
                            _cacle = new fullMinusCacle(100, 10);
                            break;
                        case "discounted":
                            _cacle = new discountedCacle(0.9);
                            break;
                        default:
                            break;
                    }
                }
    
                public double getResult(double money)
                {
                    return _cacle.getResultMoney(money);
                }
            }

    调用一下:

            static void StrategyMain(string[] args)
            {
                var cacleItem = new cacleFactory("full");
                Console.WriteLine(cacleItem.getResult(510));
    
                cacleItem = new cacleFactory("discounted");
                Console.WriteLine(cacleItem.getResult(510));
    
                Console.Read();
            } 

    这样,我们的 策略模式 就和 工厂模式 整合在一起了,实例化的过程都在工厂里面完成了,我们可以从配置文件中读取那些具体的折扣要求、满减数之类的。以后,如果还需要增加一个会员积分功能,那么我们可以写多一个策略类去实现具体的逻辑,再改写一下工厂类,原来的代码基本不会动到,出错的几率大大降低了。

    本人实际用例:

    极光推送(如果不了解推送的可以先去百度了解一下)

    我是做智能家居的,里面有个模块用到了推送功能,像开关门报警,燃气报警,SOS 紧急报警 等等。都要用到极光推送,但它们具体的数据逻辑又不一样,我们需要一个个去判断,去处理。原先没学习策略模式时,一堆 if else if else ...代码不好维护,并且之前有试过增加了一个新的推送信息,导致原先的部分推送失效,查 BUG 浪费了点时间。改进后,如有新的设备或推送要求,原先已经写好的策略类不变,只增加新的策略类,修改工厂类,我们就完成需求,工作量小了不少,而且不容易出错,以下为代码的部分截图。不用吐槽代码命名规则之类的,写得不好。

     原先写法:

     修改后:

     感谢大家的观看。

  • 相关阅读:
    Python 必备神器
    python 常用库
    Sublime Text3 配置 Python2 Python3
    Python JSON
    Sublime Text3 3143 注册码
    EFCode First 导航属性
    EF Code First:实体映射,数据迁移,重构(1)
    Entity Framework 复杂类型
    EF 7 Code First
    EF Code First 导航属性 与外键
  • 原文地址:https://www.cnblogs.com/Frank-Jan/p/8872384.html
Copyright © 2020-2023  润新知