简单工厂设计模式实现商店买牙膏收费案例过渡到结合策略模式的理由全解

来源:互联网 发布:嫁给富二代 知乎 编辑:程序博客网 时间:2024/04/20 21:27

**注:我希望你一定要上机测试运行,看懂每行代码,我的代码是可以复制过去直接运行的。

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 商城促销__简单工厂模式{    //现金收费抽象类    abstract class CashSuper    {              //注意我们写了一个抽象基类,打算让具体收费子类继承,并且把原价交给他        //方法根据不同的收费子类返回给我们一个对应的价格        public abstract double acceptCash(double money);    }    /// <summary>    /// 正常收费子类    /// </summary>    class CashNormal:CashSuper    {        public override double acceptCash(double money)        {            //由于当前的类是对应正常的收费,直接返回原价即可            return money;        }          }    /// <summary>    /// 打折收费子类    /// </summary>    class CashRebate : CashSuper    {        private double moneyRebate = 1d;        /// <summary>        /// 打折收费子类,初始化的需要得到折扣率        /// </summary>        /// <param name="moneyRebate">打折的折扣率</param>        public CashRebate(string moneyRebate)        {            this.moneyRebate = double.Parse(moneyRebate);        }        //需要把正常的价格告诉我        public override double acceptCash(double money)        {            return moneyRebate * money;        }    }    /// <summary>    /// 返利收费子类    /// </summary>    class CashReturn : CashSuper    {        //申明关于返利条件变量和具体返多少变量        private double moneyCondition = 0.0d;        private double moneyReturn = 0.0d;        /// <summary>        /// 返利子类构造函数        /// </summary>        /// <param name="moneyCondition">告诉我返利条件</param>        /// <param name="moneyReturn">告诉我返利是多少</param>        public CashReturn(double moneyCondition,double moneyReturn)        {            //保存外界传进来的数据            this.moneyCondition = moneyCondition;            this.moneyReturn = moneyReturn;        }        //需要把正常的价格告诉我        public override double acceptCash(double money)        {            //默认我们的收费是正常状态的            double result = money;            //开始根据活动内容重新计算收费            if(money >= moneyCondition)            {                result = money - moneyReturn;            }            return result;        }    }    /// <summary>    /// 现金收费工厂类    /// </summary>    class CashFactory    {        //type是活动的指令 通过活动指令我们的收费工厂给你造一个对应的收费对象        public static CashSuper createCashAccept(string type)        {            //准备接受活动对应的收费对象,默认是没有            CashSuper cs = null;            switch (type)            {                case "正常收费":                    cs = new CashNormal();                    break;                case "打8折":                    cs = new CashRebate("0.8");                    break;                case "满100返20":                    cs = new CashReturn(100, 20);                    break;                default:                    break;            }            //把根据活动指令造出来的收费对象抛出去            return cs;        }    }}using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 商城促销__策略模式{    class Program    {        static void Main(string[] args)        {            //开始接受io设备上得到的物品价格,并且保存在内存当中            Console.Write("输入当前购买的牙膏单价: ");            string goodPrice = Console.ReadLine();            Console.Write("输入用户购买的牙膏数量: ");            string goodCount = Console.ReadLine();            Console.Write("输入当前的活动指令只能是数字后面的文字内容:{1.打8折 2.满100返20 3.正常收费}\n");            string strRule = Console.ReadLine();            //开始计算牙膏总价            double total = double.Parse(goodPrice) * double.Parse(goodCount);            //先通过活动规则来通过现金收费工厂得到对应的收费对象            CashSuper cash = CashFactory.createCashAccept(strRule);            //开始真正计算开销,并且把正常的总价传过去            double lastCostMoney = cash.acceptCash(total);            //向控制台输出消费,给用户看看消费情况            Console.WriteLine(lastCostMoney);        }    }}问题分析:假如我们想增加满1000积分减少100元的活动,以及满500块送一个马桶的商品。这个时候我们是需要增加对应的收费子类,这个是可以的,但是我们还需要拿到收费工厂类去里面增加代码。简单工厂模式的优点分析:由于我们采用了收费工厂类来封装了收费这个变化点,因此不至于让我们的收费方式一改变就直接改客户端代码,也是很不错的。这个时候问题来了,我们的工厂类是不是很危险,如果被乱改,意味着啥,并且还要重新参与编译,假如我们把这个工厂类被打成dll,那么由于我们商城的需求导致我们的dll必须重新编写和编译。因此简单工厂在我们的商城收费案例里并不好用,其实关于商城的活动打折,收费,送礼物都可以看成一种针对收费的算法,如果我们把这种变化的算法封装起来,这样就不会因为收费规则不同而导致我们改其他地方的代码。因此我们就引出了我们牛B的策略设计模式。

这里写图片描述

工厂模式结合策略模式代码马上登场

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 商城促销__策略模式{    //现金收费抽象类    abstract class CashSuper    {              //注意我们写了一个抽象基类,打算让具体收费子类继承,并且把原价交给他        //方法根据不同的收费子类返回给我们一个对应的价格        public abstract double acceptCash(double money);    }    /// <summary>    /// 正常收费子类    /// </summary>    class CashNormal:CashSuper    {        public override double acceptCash(double money)        {            //由于当前的类是对应正常的收费,直接返回原价即可            return money;        }          }    /// <summary>    /// 打折收费子类    /// </summary>    class CashRebate : CashSuper    {        private double moneyRebate = 1d;        /// <summary>        /// 打折收费子类,初始化的需要得到折扣率        /// </summary>        /// <param name="moneyRebate">打折的折扣率</param>        public CashRebate(string moneyRebate)        {            this.moneyRebate = double.Parse(moneyRebate);        }        //需要把正常的价格告诉我        public override double acceptCash(double money)        {            return moneyRebate * money;        }    }    /// <summary>    /// 返利收费子类    /// </summary>    class CashReturn : CashSuper    {        //申明关于返利条件变量和具体返多少变量        private double moneyCondition = 0.0d;        private double moneyReturn = 0.0d;        /// <summary>        /// 返利子类构造函数        /// </summary>        /// <param name="moneyCondition">告诉我返利条件</param>        /// <param name="moneyReturn">告诉我返利是多少</param>        public CashReturn(double moneyCondition,double moneyReturn)        {            //保存外界传进来的数据            this.moneyCondition = moneyCondition;            this.moneyReturn = moneyReturn;        }        //需要把正常的价格告诉我        public override double acceptCash(double money)        {            //默认我们的收费是正常状态的            double result = money;            //开始根据活动内容重新计算收费            if(money >= moneyCondition)            {                result = money - moneyReturn;            }            return result;        }    }    /// <summary>    /// 现金收费工厂类    /// </summary>    class CashFactory    {        //type是活动的指令 通过活动指令我们的收费工厂给你造一个对应的收费对象        public static CashSuper createCashAccept(string type)        {            //准备接受活动对应的收费对象,默认是没有            CashSuper cs = null;            switch (type)            {                case "正常收费":                    cs = new CashNormal();                    break;                case "打8折":                    cs = new CashRebate("0.8");                    break;                case "满100返20":                    cs = new CashReturn(100, 20);                    break;                default:                    break;            }            //把根据活动指令造出来的收费对象抛出去            return cs;        }    }}  /// <summary>    /// 收费策策略配置表    /// </summary>    class CashContext    {        //申明一个收费变量维护当前收费策略对象        private CashSuper cs = null;        //通过构造方法,传入具体的收费策略 注意是指令不是具体策略对象        public CashContext(string type)        {            switch (type)            {                case "正常收费":                    //正常收费的策略                    cs = new CashNormal();                    break;                case "打8折":                    //活动打8折的策略                    cs = new CashRebate("0.8");                    break;                case "满100返20":                    //满100返回20的策略                    cs = new CashReturn(100, 20);                    break;                default:                    break;            }        }        //根据不同的收费策略,来获取不同的收费        public double GetResult(double money)        {            return cs.acceptCash(money);        }    }}using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 商城促销__策略模式{    class Program    {        static void Main(string[] args)        {            //开始接受io设备上得到的物品价格,并且保存在内存当中            Console.Write("输入当前购买的牙膏单价: ");            string goodPrice = Console.ReadLine();            Console.Write("输入用户购买的牙膏数量: ");            string goodCount = Console.ReadLine();            Console.Write("输入当前的活动指令只能是数字后面的文字内容:{1.打8折 2.满100返20 3.正常收费}\n");            string strRule = Console.ReadLine();            //开始计算牙膏总价            double total = double.Parse(goodPrice) * double.Parse(goodCount);            //先通过活动规则来通过现金收费工厂得到对应的收费对象            //CashSuper cash = CashFactory.createCashAccept(strRule);            //我们选择策略模式里面的策略配置表,可以得到当前的收费策略计算出对应收费            //定义得到保存的收费策略对象的配置表            CashContext context = null;            context = new CashContext(strRule);            //既然我们通过策略配置变得到了当前收费策略,那么我们就可以            //把当前的开销传给策略对象进行计算后得到最终的收费            double lastCostMoney = context.GetResult(total);            //向控制台输出消费,给用户看看消费情况            Console.WriteLine(lastCostMoney);        }    }

这里写图片描述
设计模式对比:简单工厂模式对客户端来说,假如我是有牙膏的总价格,也有活动的内容,这个时候我不想写具体代码,我需要利用其他代码,那么我是先通过工厂类得到对应活动的收费对象那么我客户端是和这个工厂类是耦合的,也就是我必须认识这个工厂类CashFactory,并且还需要和具体的
CashSupper父类,那么和2个类进行耦合了。
那么策略模式我们是只要得到策略配置对象就可以得到我们想要的收费,也就是CashContext对象,和这个对象耦合。
那么应对需求变化的时候,哪个更容易维护呢,策略模式来说,我们客户端也就是使用CashContext对象得到收费的接口是完全可以不动的,我们只需要增加对应的收费策略类,然后在更改CashContext配置表的构造方法。
现在就简单工厂来说,增加了收费策略,我们增加对应的收费类,还必须改工厂类。
其实最主要的是我们的客户端用了策略模式后完全不需要认识CashSupper也就是具体的收费策略,你活动变了,我客户端程序不用改,这样你可以随便去修改策略。**

阅读全文
0 0