您的位置:首页 > 其它

策略模式

2015-09-24 19:38 525 查看

策略模式

前言

接着好几天前的设计模式再写一篇,不知道谁看过<<男人帮>>这部电视剧,黄磊老师还有红雷大哥演的,里面有以下经典台词:



(1)自从我们睁开眼睛看这个世界的第一天起, 我们看到的就只有两种人,男人和女人。 他们分属于两大不同的阵营,为了彻底收服对方,大家互相往死里掐。

(2)根据一个遥远的传说,说有一种东西叫爱情,可以彻底终结这场战争。于是大家纷纷的赶紧去寻找,赶紧去幻想, 找到头破血流才发现,原来这个感情也是另一些人在书房里炮制出来的。 于是大家更加绝望,更加痛苦,更加互相的往死里掐。







场景案例

尤其是上面这几句,让我想起了一同学和他一女朋友的故事,一次活动中,某某哥认识了某某嫂,哪个一见钟情啊,简直是看不见某某嫂就吃不下饭去,写不下代码,在追求中没少费工夫,比如:送个小礼物,请客吃饭,搞点小浪漫等等.



(1)第一阶段赠送小礼物代码如下:

//第一阶段 送小礼物
        public static void SendGift()
        {
            Console.WriteLine("送给女方精美小礼物!");
        }
 
        static void Main(string[] args)
        {
            //第一阶段 
            SendGift();
        }


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

//第一阶段 送小礼物
        public static void SendGift()
        {
            Console.WriteLine("送给女方精美小礼物!");
        }
 
        //添加 第二阶段 请客吃饭
        public static void Eat()
        {
            Console.WriteLine("请女生吃牛排!");
        }
 
        static void Main(string[] args)
        {
            //第一阶段 
            //SendGift(); //此时第一阶段已经不需要了所以注销掉进入第二阶段
 
            //第二阶段
            Eat();
        }


(3)经过之前两个阶段的接触,两个人已经在一起了,在一起就避免不了在热恋中经历一些浪漫的事情,所以第三阶段就是:制造浪漫,代码如下:

//第一阶段 送小礼物
        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函数中的调用修改成进入新的阶段,那么我们怎么样能避免,在进入新阶段后不去修改调用的代码呢?当然这个肯定难不倒你,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace 策略模式
{
    class Program
    {    
        //第一阶段 送小礼物
        public static void SendGift()
        {
            Console.WriteLine("送给女方精美小礼物!");
        }
        //第二阶段 请客吃饭
 
        public static void Eat()
        {
            Console.WriteLine("请女生吃牛排");
        }
 
        //第三阶段 搞点浪漫
 
        public static void Romantic()
        {
            Console.WriteLine("精心***了红酒、晚餐与蜡烛,等待女友回家!");
        }
        static void Main(string[] args)
        {
            Console.WriteLine("现在是第几阶段?:");
 
            string level = Console.ReadLine();
 
            switch (level)
            {
                case "one"://第一阶段 
                    SendGift();
                    break;
                case "two"://第二阶段
                    Eat();
                    break;
                case "three": //第三阶段
                    Romantic();
                    break;
                default:
                    Console.WriteLine("没这个打算凑什么热闹?");
                    break;
            }
        }
    }
}


这样我们就解决了在两人进入新的阶段后,无需修改main方法中的代码.



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







引入策略模式

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



策略模式类图如下:






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






模式出了类型那么我们写代码当然就不难了.



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



案例如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace 策略模式
{
    //追女孩策略抽象类
 
    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 strategy;
 
        public PursueaGirlContext(PursueaGirlStrategy strategy)
        {
            this.strategy = strategy;
        }
 
        //调用策略的公共接口方法
 
        public void ContextJustDoIt()
        {
            if (this.strategy!=null)
            {
                this.strategy.JustDoIt();
            }
        }
    }
    class Program
    {    
       
        static void Main(string[] args)
        {
           //定义追女孩策略上下文对象
 
            PursueaGirlContext context = null;
 
            Console.WriteLine("现在是第几阶段?");
 
            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();
 
        }
    }
}


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







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

概念上理解:

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



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







策略与工厂

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



我们使用工厂之后的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace 策略模式
{
    //追女孩策略抽象类
 
    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 PursueaGirlContext
    {
        PursueaGirlStrategy staregy;
        public PursueaGirlContext(PursueaGirlStrategy strategy)
        {
            this.staregy = strategy;
        }
 
        //调用策略的公共接口方法
        public void ContextJustdoit()
        {
            if (this.staregy != null)
            {
                this.staregy.Justdoit();
            }
        }
 
    }
 
    //提供策略的工厂
    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;
        }
    }
 
    class Program
    {    
       
        static void Main(string[] args)
        {
            Console.Write("现在是第几阶段?:");
            string level = Console.ReadLine(); //代表当前是哪个阶段
 
            //定义追女孩策略上下文对象
            PursueaGirlContext context = FactoryStrategy.GetStrategy(level);
 
            //统一的策略调用模式
            context.ContextJustdoit();
 
        }
    }
}


这样,我们以后如果有新的策略只需要增加新的策略类,修改工厂即可,那么肯定有同学会问,这样只不过是把修改客户端移动到工厂里面了,将来还是需要工厂,没办法彻底解决调用修改的,怎么办?别着急,以后慢慢学.先掌握这种思想.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: