设计模式系列-策略模式

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

创新互联长期为超过千家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为资源企业提供专业的成都网站设计、成都网站建设资源网站改版等技术服务。拥有10多年丰富建站经验和众多成功案例,为您定制开发。

       列举部分台词如下:

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

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

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

  1. //第一阶段 送小礼物 
  2.     public static void SendGift()  
  3.     {  
  4.         Console.WriteLine("送给女方精美小礼物!");  
  5.     }  
  6.  
  7.     static void Main(string[] args)  
  8.     {  
  9.         //第一阶段  
  10.         SendGift();  
  11.     } 

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

  1. //第一阶段 送小礼物 
  2.  public static void SendGift()  
  3.  {  
  4.      Console.WriteLine("送给女方精美小礼物!");  
  5.  }  
  6.  
  7.  //添加 第二阶段 请客吃饭 
  8.  public static void Eat()  
  9.  {  
  10.      Console.WriteLine("请女生吃牛排!");  
  11.  }  
  12.  
  13.  static void Main(string[] args)  
  14.  {  
  15.      //第一阶段  
  16.      //SendGift(); //此时第一阶段已经不需要了所以注销掉进入第二阶段 
  17.  
  18.      //第二阶段 
  19.      Eat();  
  20.  } 

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

  1. //第一阶段 送小礼物 
  2.       public static void SendGift()  
  3.       {  
  4.           Console.WriteLine("送给女方精美小礼物!");  
  5.       }  
  6.  
  7.       //添加 第二阶段 请客吃饭 
  8.       public static void Eat()  
  9.       {  
  10.           Console.WriteLine("请女生吃牛排!");  
  11.       }  
  12.  
  13.       //添加 第三阶段 浪漫:烛光晚餐等待女友 
  14.       public static void Romantic()  
  15.       {  
  16.           Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");  
  17.       }  
  18.  
  19.       static void Main(string[] args)  
  20.       {  
  21.           //第一阶段  
  22.           //SendGift(); //此时第一阶段已经不需要了所以注销掉进入第二阶段 
  23.  
  24.           //第二阶段 
  25.           //Eat(); //此时第二阶段也已经经过,所以注销掉、进入第三阶段 
  26.  
  27.           //第三阶段 
  28.           Romantic();  
  29.       }  
             看了某某哥追某某嫂的经过后,我们会发现,每当进入一个新阶段的时候,我们就需要去修改我们的代码,加入新的追女策略,并且将main函数中的调用修改成进入新的阶段,那么我们怎么样能避免,在进入新阶段后不去修改调用的代码呢?当然这个肯定难不倒你,代码如下:
  1. //第一阶段 送小礼物 
  2.         public static void SendGift()  
  3.         {  
  4.             Console.WriteLine("送给女方精美小礼物!");  
  5.         }  
  6.  
  7.         //添加 第二阶段 请客吃饭 
  8.         public static void Eat()  
  9.         {  
  10.             Console.WriteLine("请女生吃牛排!");  
  11.         }  
  12.  
  13.         //添加 第三阶段 浪漫:烛光晚餐等待女友 
  14.         public static void Romantic()  
  15.         {  
  16.             Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");  
  17.         }  
  18.  
  19.         static void Main(string[] args)  
  20.         {  
  21.             Console.Write("现在是第几阶段?:");  
  22.             string level = Console.ReadLine(); //代表当前是哪个阶段 
  23.             switch (level)  
  24.             {  
  25.                 case "one"://第一阶段  
  26.                     SendGift();  
  27.                     break;  
  28.                 case "two"://第二阶段 
  29.                     Eat();  
  30.                     break;  
  31.                 case "three": //第三阶段 
  32.                     Romantic();  
  33.                     break;  
  34.                 default:  
  35.                     Console.WriteLine("没这个打算凑什么热闹?");  
  36.                     break;  
  37.             }  
  38.         }  
                 这样我们就解决了在两人进入新的阶段后,无需修改main方法中的代码!输出结果如下:

   设计模式系列-策略模式

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

          2、引入策略模式

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

          策略模式类图如下:

设计模式系列-策略模式

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

设计模式系列-策略模式

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

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

  1. //追女孩策略抽象类 
  2.  public abstract class PursueaGirlStrategy  
  3.  {  
  4.      //追女孩策略中都有一个统一的接口,就是行动。 
  5.      public abstract void Justdoit();  
  6.  }  
          ② 接下来,就是追女孩策略中,各个环节策略的实现啦,代码如下:
  1. //第一阶段 送小礼物 
  2.    public class SendGiftStrategy : PursueaGirlStrategy  
  3.    {  
  4.        public override void Justdoit()  
  5.        {  
  6.            Console.WriteLine("送给女方精美小礼物!");  
  7.        }  
  8.    }  
  9.  
  10.    //第二阶段 请客吃饭 
  11.    public class EatStrategy : PursueaGirlStrategy  
  12.    {  
  13.        public override void Justdoit()  
  14.        {  
  15.            Console.WriteLine("请女生吃牛排!");  
  16.        }  
  17.    }  
  18.  
  19.    //第三阶段 浪漫:烛光晚餐等待女友 
  20.    public class RomanticStrategy : PursueaGirlStrategy  
  21.    {  
  22.        public override void Justdoit()  
  23.        {  
  24.            Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");  
  25.        }  
  26.    }  
         ③ 最后就是,承载策略实例,提供统一调用的策略上下文啦。代码如下:
  1. //策略的宿主 承载当前需要执行的策略 
  2.    public class PursueaGirlContext  
  3.    {  
  4.        SendGiftStrategy staregy;  
  5.        public PursueaGirlContext(SendGiftStrategy strategy)  
  6.        {  
  7.            this.staregy = strategy;  
  8.        }  
  9.  
  10.        //调用策略的公共接口方法 
  11.        public void ContextJustdoit()  
  12.        {  
  13.            if (this.staregy != null)  
  14.            {  
  15.                this.staregy.Justdoit();  
  16.            }  
  17.        }  
  18.  
  19.    }  
  20.       main方法将来调用如下:  
  21.  
  22.  static void Main(string[] args)  
  23.        {  
  24.            //定义追女孩策略上下文对象 
  25.            PursueaGirlContext context = null;  
  26.            Console.Write("现在是第几阶段?:");  
  27.            string level = Console.ReadLine(); //代表当前是哪个阶段 
  28.            switch (level)  
  29.            {  
  30.                case "one"://第一阶段  
  31.                    context = new PursueaGirlContext(new SendGiftStrategy());  
  32.                    break;  
  33.                case "two"://第二阶段 
  34.                    context = new PursueaGirlContext(new EatStrategy());  
  35.                    break;  
  36.                case "three": //第三阶段 
  37.                    context = new PursueaGirlContext(new RomanticStrategy());  
  38.                    break;  
  39.                default:  
  40.                    Console.WriteLine("没这个打算凑什么热闹?");  
  41.                    break;  
  42.            }  
  43.  
  44.            //统一的策略调用模式 
  45.            context.ContextJustdoit();  
  46.        }  
          好的,策略模式与我们的场景先告一段落把。这个时候可能有的人就会问啦,策略模式跟工厂模式很想啊,都是提供一个统一的接口,有不同的实例去实例化。那么我们来看看策略模式与工厂模式的区别吧。

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

          概念上理解:

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

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

          4、策略与工厂谈恋爱

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

           ①工厂代码代码如下:

  1. //提供策略的工厂 
  2.     public class FactoryStrategy  
  3.     {  
  4.         //根据客户端参数创建策略 
  5.         public static PursueaGirlContext GetStrategy(string level)  
  6.         {  
  7.             //定义追女孩策略上下文对象 
  8.             PursueaGirlContext context = null;  
  9.             switch (level)  
  10.             {  
  11.                 case "one"://第一阶段  礼物 
  12.                     context = new PursueaGirlContext(new SendGiftStrategy());  
  13.                     break;  
  14.                 case "two"://第二阶段 吃饭 
  15.                     context = new PursueaGirlContext(new EatStrategy());  
  16.                     break;  
  17.                 case "three": //第三阶段 浪漫 
  18.                     context = new PursueaGirlContext(new RomanticStrategy());  
  19.                     break;  
  20.                 case "four"://第四阶段 结婚 
  21.                     context = new PursueaGirlContext(new MarriedStrategy());  
  22.                     break;  
  23.                 default:  
  24.                     context = null;  
  25.                     break;  
  26.             }  
  27.             return context;  
  28.         }  
  29.     }  
           ② 有了工厂后的客户端(main)代码如下:
  1. static void Main(string[] args)  
  2.        {  
  3.             
  4.            Console.Write("现在是第几阶段?:");  
  5.            string level = Console.ReadLine(); //代表当前是哪个阶段 
  6.  
  7.            //定义追女孩策略上下文对象 
  8.            PursueaGirlContext context = FactoryStrategy.GetStrategy(level);  
  9.  
  10.            //统一的策略调用模式 
  11.            context.ContextJustdoit();  
  12.        }  
 
           ③ 完整代码如下:
  1. //追女孩策略抽象类 
  2.     public abstract class PursueaGirlStrategy  
  3.     {  
  4.         //追女孩策略中都有一个统一的接口,就是行动。 
  5.         public abstract void Justdoit();  
  6.     }  
  7.  
  8.     //第一阶段 送小礼物 
  9.     public class SendGiftStrategy : PursueaGirlStrategy  
  10.     {  
  11.         public override void Justdoit()  
  12.         {  
  13.             Console.WriteLine("送给女方精美小礼物!");  
  14.         }  
  15.     }  
  16.  
  17.     //第二阶段 请客吃饭 
  18.     public class EatStrategy : PursueaGirlStrategy  
  19.     {  
  20.         public override void Justdoit()  
  21.         {  
  22.             Console.WriteLine("请女生吃牛排!");  
  23.         }  
  24.     }  
  25.  
  26.     //第三阶段 浪漫:烛光晚餐等待女友 
  27.     public class RomanticStrategy : PursueaGirlStrategy  
  28.     {  
  29.         public override void Justdoit()  
  30.         {  
  31.             Console.WriteLine("精心制作了红酒、晚餐与蜡烛,等待女友回家!");  
  32.         }  
  33.     }  
  34.  
  35.     //添加第四阶段 结婚 
  36.     public class MarriedStrategy : PursueaGirlStrategy  
  37.     {  
  38.         public override void Justdoit()  
  39.         {  
  40.             Console.WriteLine("两人民政局领证!");  
  41.         }  
  42.     }  
  43.  
  44.     //提供策略的工厂 
  45.     public class FactoryStrategy  
  46.     {  
  47.         //根据客户端参数创建策略 
  48.         public static PursueaGirlContext GetStrategy(string level)  
  49.         {  
  50.             //定义追女孩策略上下文对象 
  51.             PursueaGirlContext context = null;  
  52.             switch (level)  
  53.             {  
  54.                 case "one"://第一阶段  礼物 
  55.                     context = new PursueaGirlContext(new SendGiftStrategy());  
  56.                     break;  
  57.                 case "two"://第二阶段 吃饭 
  58.                     context = new PursueaGirlContext(new EatStrategy());  
  59.                     break;  
  60.                 case "three": //第三阶段 浪漫 
  61.                     context = new PursueaGirlContext(new RomanticStrategy());  
  62.                     break;  
  63.                 case "four"://第四阶段 结婚 
  64.                     context = new PursueaGirlContext(new MarriedStrategy());  
  65.                     break;  
  66.                 default:  
  67.                     context = null;  
  68.                     break;  
  69.             }  
  70.             return context;  
  71.         }  
  72.     }  
  73.  
  74.     //策略的宿主 承载当前需要执行的策略 
  75.     public class PursueaGirlContext  
  76.     {  
  77.         PursueaGirlStrategy staregy;  
  78.         public PursueaGirlContext(PursueaGirlStrategy strategy)  
  79.         {  
  80.             this.staregy = strategy;  
  81.         }  
  82.  
  83.         //调用策略的公共接口方法 
  84.         public void ContextJustdoit()  
  85.         {  
  86.             if (this.staregy != null)  
  87.             {  
  88.                 this.staregy.Justdoit();  
  89.             }  
  90.         }  
  91.  
  92.     }  
  93.     static void Main(string[] args)  
  94.         {  
  95.              
  96.             Console.Write("现在是第几阶段?:");  
  97.             string level = Console.ReadLine(); //代表当前是哪个阶段 
  98.  
  99.             //定义追女孩策略上下文对象 
  100.             PursueaGirlContext context = FactoryStrategy.GetStrategy(level);  
  101.  
  102.             //统一的策略调用模式 
  103.             context.ContextJustdoit();  
  104.         }  
        这样我们以后如果有新的策略只需要增加新的策略类,修改工厂即可,那么细心的朋友问了,这样只不过是把修改客户端移到工厂里面了,将来还是需要工厂,没关系彻底解决调用修改的话,我们将来可以利用反射!以后不管修改还是新增我们都能很好的去应对了。

分享文章:设计模式系列-策略模式
浏览地址:http://ybzwz.com/article/jiphgj.html