zoukankan      html  css  js  c++  java
  • 设计模式之二 策略模式

     今天下班回家,吃完晚饭后在网上闲逛,看了看电视剧《男人帮》的经典台词,感觉很经典,虽然这个电视剧我早已经在上个月就看完了,但是看了看里面的经典开场白和台词,还是不由自主的伸出大拇指,赞啊!

           列举部分台词如下:

          (1)自从我们睁开眼睛看这个世界的第一天起, 我们看到的就只有两种人,男人和女人。 他们分属于两大不同的阵营,为了彻底收服对方,大家互相往死里掐。 
          (2)根据一个遥远的传说,说有一种东西叫爱情,可以彻底终结这场战争。 于是大家纷纷的赶紧去寻找,赶紧去幻想, 找到头破血流才发现,原来这个感情也是另一些人在书房里炮制出来的。 于是大家更加绝望,更加痛苦,更加互相的往死里掐。 

            1、场景案例
           尤其是上面这几句,让我想起了我一同事(这里用“某某哥”代替)和他女朋友的故事(这里用“某某嫂”代替),一次活动中,某某哥认识了某某嫂,那个一见钟情呀,简直是看不见某某嫂就吃不下饭、写不下代码呀,在追求中也没少费工夫。比如:送小礼物,请客吃饭,搞浪漫等等,我们就把这几个阶段分别用代码模拟一下把!

               ①第一阶段赠送小礼物代码如下:

    复制代码
           //第一阶段 送小礼物
            public static void SendGift()
            {
                Console.WriteLine("送给女方精美小礼物!");
            }

            static void Main(string[] args)
            {
                //第一阶段 
                SendGift();
            }
    复制代码

               ② 此时、通过送精美小礼物女方已经愿意与男方接触,这时就可以一起吃饭了,代码如下:

    复制代码
            //第一阶段 送小礼物
            public static void SendGift()
            {
                Console.WriteLine("送给女方精美小礼物!");
            }

            //添加 第二阶段 请客吃饭
            public static void Eat()
            {
                Console.WriteLine("请女生吃牛排!");
            }

            static void Main(string[] args)
            {
                //第一阶段 
                
    //SendGift(); //此时第一阶段已经不需要了所以注销掉进入第二阶段

                
    //第二阶段
                Eat();
            }
    复制代码

             ③ 经过之前阶段的接触,两人已经在一起了,在一起就免不了在热恋中经历浪漫情节,第三阶段:制造浪漫、代码如下:

    复制代码
          //第一阶段 送小礼物
            public static void SendGift()
            {
                Console.WriteLine("送给女方精美小礼物!");
            }

            //添加 第二阶段 请客吃饭
            public static void Eat()
            {
                Console.WriteLine("请女生吃牛排!");
            }

            //添加 第三阶段 浪漫:烛光晚餐等待女友
            public static void Romantic()
            {
                Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");
            }

            static void Main(string[] args)
            {
                //第一阶段 
                
    //SendGift(); //此时第一阶段已经不需要了所以注销掉进入第二阶段

                
    //第二阶段
                
    //Eat(); //此时第二阶段也已经经过,所以注销掉、进入第三阶段

                
    //第三阶段
                Romantic();
            }
    复制代码

             看了某某哥追某某嫂的经过后,我们会发现,每当进入一个新阶段的时候,我们就需要去修改我们的代码,加入新的追女策略,并且将main函数中的调用修改成进入新的阶段,那么我们怎么样能避免,在进入新阶段后不去修改调用的代码呢?当然这个肯定难不倒你,代码如下:

    复制代码
           //第一阶段 送小礼物
            public static void SendGift()
            {
                Console.WriteLine("送给女方精美小礼物!");
            }

            //添加 第二阶段 请客吃饭
            public static void Eat()
            {
                Console.WriteLine("请女生吃牛排!");
            }

            //添加 第三阶段 浪漫:烛光晚餐等待女友
            public static void Romantic()
            {
                Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");
            }

            static void Main(string[] args)
            {
                Console.Write("现在是第几阶段?:");
                string level = Console.ReadLine(); //代表当前是哪个阶段
                switch (level)
                {
                    case "one"://第一阶段 
                        SendGift();
                        break;
                    case "two"://第二阶段
                        Eat();
                        break;
                    case "three"//第三阶段
                        Romantic();
                        break;
                    default:
                        Console.WriteLine("没这个打算凑什么热闹?");
                        break;
                }
            }
    复制代码

              这样我们就解决了在两人进入新的阶段后,无需修改main方法中的代码!输出结果如下:

       

             那么如果这时两人已经到了谈婚论嫁的时候,该怎么办呢?也就是要在新加入一个阶段叫做结婚呢?

              2、引入策略模式

             普通的办法还是要去新增方法,在修改调用代码!那我们有没有办法呢?别着急,先看看策略模式、定义如下:“它定义了算法家族,分别封装起来,让他们之间可以互相替换,次模式让算法的变化,不会影响到使用算法的客户”。

              策略模式类图如下:

             那么使用策略模式改装,我们上面场景的类图如下:

              模拟出了类型那么我们写代码当然也就不难啦。

              ① 首先呢,我们需要抽象出来追女孩策略,这个策略里面有一个公共的接口就是去做(也就是行动的意思),例如:送礼物、吃饭、浪漫,都是需要人去做去行动的。

    复制代码
        //追女孩策略抽象类
        public abstract class PursueaGirlStrategy
        {
            //追女孩策略中都有一个统一的接口,就是行动。
            public abstract void Justdoit();
        }
    复制代码

             ② 接下来,就是追女孩策略中,各个环节策略的实现啦,代码如下:

    复制代码
     //第一阶段 送小礼物
        public class SendGiftStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("送给女方精美小礼物!");
            }
        }

        //第二阶段 请客吃饭
        public class EatStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("请女生吃牛排!");
            }
        }

        //第三阶段 浪漫:烛光晚餐等待女友
        public class RomanticStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");
            }
        }
    复制代码

             ③ 最后就是,承载策略实例,提供统一调用的策略上下文啦。代码如下:

    复制代码
     //策略的宿主 承载当前需要执行的策略
        public class PursueaGirlContext
        {
            PursueaGirlStrategy staregy;
            public PursueaGirlContext(PursueaGirlStrategy strategy)
            {
                this.staregy = strategy;
            }

            //调用策略的公共接口方法
            public void ContextJustdoit()
            {
                if (this.staregy != null)
                {
                    this.staregy.Justdoit();
                }
            }

        }
    复制代码

           main方法将来调用如下:

    复制代码
      static void Main(string[] args)
            {
                //定义追女孩策略上下文对象
                PursueaGirlContext context = null;
                Console.Write("现在是第几阶段?:");
                string level = Console.ReadLine(); //代表当前是哪个阶段
                switch (level)
                {
                    case "one"://第一阶段 
                        context = new PursueaGirlContext(new SendGiftStrategy());
                        break;
                    case "two"://第二阶段
                        context = new PursueaGirlContext(new EatStrategy());
                        break;
                    case "three"//第三阶段
                        context = new PursueaGirlContext(new RomanticStrategy());
                        break;
                    default:
                        Console.WriteLine("没这个打算凑什么热闹?");
                        break;
                }

                //统一的策略调用模式
                context.ContextJustdoit();
            }
    复制代码

              好的,策略模式与我们的场景先告一段落把。这个时候可能有的人就会问啦,策略模式跟工厂模式很想啊,都是提供一个统一的接口,有不同的实例去实例化。那么我们来看看策略模式与工厂模式的区别吧。

              3、策略模式与工厂模式的区别

              概念上理解:

                         ① 策略模式:是告诉上下文,我需要去做什么,至于使用怎么实现,需要上下文去使用当前对应的策略去实现。例如:项目经理(客户端)说:“我要实现即时消息功能”,那么我们程序员(上下文)就需要去寻找对应的策略(开发即时消息模块的策略)去实现。

                         ②工厂模式:是告诉工厂,此时我需要什么部件你去给我制造,例如:开发及时消息模块,我需要JS的弹出框,我就会告诉UI组(工厂),给我做一个JS弹出框,要求模仿EXT的。

              4、策略与工厂谈恋爱

               那么了解了他们之间的区别后,我们再来看上面策略模式实现的一个问题,例如:需要加入结婚策略时,还是需要增加结婚策略类,并且修改客户端(MAIN方法)中的调用代码。那么我们把提供使用策略的代码放到工厂中呢?这样我们以后就只需要增加新策略修改工厂就行啦!客户端就不用修改了。

               ①工厂代码代码如下:

    复制代码
     //提供策略的工厂
        public class FactoryStrategy
        {
            //根据客户端参数创建策略
            public static PursueaGirlContext GetStrategy(string level)
            {
                //定义追女孩策略上下文对象
                PursueaGirlContext context = null;
                switch (level)
                {
                    case "one"://第一阶段  礼物
                        context = new PursueaGirlContext(new SendGiftStrategy());
                        break;
                    case "two"://第二阶段 吃饭
                        context = new PursueaGirlContext(new EatStrategy());
                        break;
                    case "three"//第三阶段 浪漫
                        context = new PursueaGirlContext(new RomanticStrategy());
                        break;
                    case "four"://第四阶段 结婚
                        context = new PursueaGirlContext(new MarriedStrategy());
                        break;
                    default:
                        context = null;
                        break;
                }
                return context;
            }
        }
    复制代码

              ② 有了工厂后的客户端(main)代码如下:

    复制代码
       static void Main(string[] args)
            {
               
                Console.Write("现在是第几阶段?:");
                string level = Console.ReadLine(); //代表当前是哪个阶段

                
    //定义追女孩策略上下文对象
                PursueaGirlContext context = FactoryStrategy.GetStrategy(level);

                //统一的策略调用模式
                context.ContextJustdoit();
            }
    复制代码

             ③ 完整代码如下:

    复制代码
    //追女孩策略抽象类
        public abstract class PursueaGirlStrategy
        {
            //追女孩策略中都有一个统一的接口,就是行动。
            public abstract void Justdoit();
        }

        //第一阶段 送小礼物
        public class SendGiftStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("送给女方精美小礼物!");
            }
        }

        //第二阶段 请客吃饭
        public class EatStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("请女生吃牛排!");
            }
        }

        //第三阶段 浪漫:烛光晚餐等待女友
        public class RomanticStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");
            }
        }

        //添加第四阶段 结婚
        public class MarriedStrategy : PursueaGirlStrategy
        {
            public override void Justdoit()
            {
                Console.WriteLine("两人民政局领证!");
            }
        }

        //提供策略的工厂
        public class FactoryStrategy
        {
            //根据客户端参数创建策略
            public static PursueaGirlContext GetStrategy(string level)
            {
                //定义追女孩策略上下文对象
                PursueaGirlContext context = null;
                switch (level)
                {
                    case "one"://第一阶段  礼物
                        context = new PursueaGirlContext(new SendGiftStrategy());
                        break;
                    case "two"://第二阶段 吃饭
                        context = new PursueaGirlContext(new EatStrategy());
                        break;
                    case "three"//第三阶段 浪漫
                        context = new PursueaGirlContext(new RomanticStrategy());
                        break;
                    case "four"://第四阶段 结婚
                        context = new PursueaGirlContext(new MarriedStrategy());
                        break;
                    default:
                        context = null;
                        break;
                }
                return context;
            }
        }

        //策略的宿主 承载当前需要执行的策略
        public class PursueaGirlContext
        {
            PursueaGirlStrategy staregy;
            public PursueaGirlContext(PursueaGirlStrategy strategy)
            {
                this.staregy = strategy;
            }

            //调用策略的公共接口方法
            public void ContextJustdoit()
            {
                if (this.staregy != null)
                {
                    this.staregy.Justdoit();
                }
            }

        }
        static void Main(string[] args)
            {
               
                Console.Write("现在是第几阶段?:");
                string level = Console.ReadLine(); //代表当前是哪个阶段

                
    //定义追女孩策略上下文对象
                PursueaGirlContext context = FactoryStrategy.GetStrategy(level);

                //统一的策略调用模式
                context.ContextJustdoit();
            }
    复制代码

            这样我们以后如果有新的策略只需要增加新的策略类,修改工厂即可,那么细心的朋友问了,这样只不过是把修改客户端移到工厂里面了,将来还是需要工厂,没关系彻底解决调用修改的话,我们将来可以利用反射!以后不管修改还是新增我们都能很好的去应对了。

  • 相关阅读:
    DB9 ------ 接口定义
    以太网 ------ Auto-Negotiation(自动协商)
    Qt ------ 添加某个功能,比如(QSerialPort)注意事项
    Modbus
    Centos7.5 安装JDK1.8 步骤
    Kafka 消息中间件
    使用RabbitMQ实现分布式事务
    RabbitMq的环境安装
    RabbitMQ消息中间件的用法
    基于Docker+Jenkins实现自动化部署
  • 原文地址:https://www.cnblogs.com/TNSSTAR/p/2971120.html
Copyright © 2011-2022 走看看