[设计模式] 策略模式(Strategy)

reference to : http://www.cnblogs.com/spring5/archive/2011/10/20/2485291.html

一、概要
我们构建程序的时候,会遇到这样的状况,对象有某个行为,但是在不同的场景中,使用策略模式,可以把它们一个个封装起来,并且使它们可相互替换,而起使得算法可独立于使用它的客户而变化。
 
二、生活举例
对于一个商店来讲,对不同的客户要报不同的价格,比如:
(1)对普通客户或者是新客户报的是全价
(2)对老客户(会员)报的价格,要给予一定的折扣
(3)对大客户(批发)报的价格,根据大客户购买量,给予一定的折扣
(4)根据不同的时间段,例如工作日和节假日等,可能价格仍然不同。
处理复杂的报价功能,就会用到策略模式。
 
三、实现思路

四、类图

五、注意点
1、策略模式的设计原则即把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。
2、策略模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户,即把会变化的内容取出并封装起来,以便以后可以轻易地改动或扩充部分,而不影响不需要变化的其他部分;这样便可以动态的改变对象的行为。
 
六、实例
1、说明:通过策略模式,简单工厂+策略模式,反射+策略模式三种方式实现需求,然后对比三种实现方式。
2、语言:C#
3、虚拟需求:《机房收费系统》计费方式:1、学生周一到周五免费 2、学生周六,周日1元/小时 3、临时用户任何时间都是1.5元/小时

代码1.0(策略模式标准实现):

using System;

namespace 策略模式
{
    class Program
    {
        private string type;
        public Program(string type)
        {
            this.type = type;
        }
        static void Main(string[] args)
        {

            Program pro = new Program("学生,周一到周五");
            //Program pro = new Program("学生,周六周日");
            //Program pro = new Program("临时用户,任意时间");
            switch (pro.type)
            {
                case "学生,周一到周五":
                    Contest c1 = new Contest(new concreteStrategyA());
                    c1.ContestInterface();
                    break;
                case "学生,周六周日":
                    Contest c2 = new Contest(new concreteStrategyB());
                    c2.ContestInterface();
                    break;
                case "临时用户,任意时间":
                     Contest c3 = new Contest(new concreteStrategyC());
                    c3.ContestInterface();
                    break;
            }
        }
    }
    abstract class Strategy
    {
        //算法方法
        public abstract void AlgorithmInterface();

    }

    //具体算法:学生周一到周五免费
    class concreteStrategyA : Strategy
    {
        //算法A实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("学生周一到周五免费");
        }
    }
    //具体算法:学生周六,周日1元/小时
    class concreteStrategyB : Strategy
    {
        //算法B实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("学生周六,周日1元/小时");
        }
    }

    //具体算法:临时用户任何时间都是1.5元/小时
    class concreteStrategyC : Strategy
    {
        //算法C实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("临时用户任何时间都是1.5元/小时");
        }
    }

    class Contest
    {
        Strategy strategy;
        public Contest(Strategy strategy)
        {
            this.strategy = strategy;
        }
        //上下文接口
        public void ContestInterface()
        {
            strategy.AlgorithmInterface();
        }
    }
}

代码2.0(策略模式+简单工厂):

<span style="color:#000000;">using System;

namespace 策略模式和简单工厂结合
{
    class Program
    {
        static void Main(string[] args)
        {
            Contest c1 = new Contest("学生,周一到周五");
            c1.ContestInterface();
            Contest c2 = new Contest("学生,周六周日");
            c2.ContestInterface();
            Contest c3 = new Contest("临时用户,任意时间");
            c3.ContestInterface();
        }
    }
    abstract class Strategy
    {
        //算法方法
        public abstract void AlgorithmInterface();

    }

    //具体算法:学生周一到周五免费
    class concreteStrategyA : Strategy
    {
        //算法A实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("学生周一到周五免费");
        }
    }
    //具体算法:学生周六,周日1元/小时
    class concreteStrategyB : Strategy
    {
        //算法B实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("学生周六,周日1元/小时");
        }
    }

    //具体算法:临时用户任何时间都是1.5元/小时
    class concreteStrategyC : Strategy
    {
        //算法C实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("临时用户任何时间都是1.5元/小时");
        }
    }

    class Contest
    {
        Strategy strategy;
        public Contest(string type)
        {
            switch (type)
            {
                case "学生,周一到周五":
                    concreteStrategyA a = new concreteStrategyA();
                    strategy = a;
                    break;
                case "学生,周六周日":
                    concreteStrategyB b = new concreteStrategyB();
                    strategy = b;
                    break;
                case "临时用户,任意时间":
                    concreteStrategyC c = new concreteStrategyC();
                    strategy = c;
                    break;
            }
        }
        //上下文接口
        public void ContestInterface()
        {
            strategy.AlgorithmInterface();
        }

    }
}</span>

代码3.0(策略模式+反射):

<span style="color:#000000;">using System;
using System.Reflection;

namespace 策略模式和反射结合
{
    class Program
    {
        static void Main(string[] args)
        {
            Contest c1= new Contest("concreteStrategyA");
            c1.ContestInterface();
            Contest c2 = new Contest("concreteStrategyB");
            c2.ContestInterface();
            Contest c3 = new Contest("concreteStrategyC");
            c3.ContestInterface();
        }
    }
    abstract class Strategy
    {
        //算法方法
        public abstract void AlgorithmInterface();

    }

    //具体算法:学生周一到周五免费
    class concreteStrategyA : Strategy
    {
        //算法A实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("学生周一到周五免费");
        }
    }
    //具体算法:学生周六,周日1元/小时
    class concreteStrategyB : Strategy
    {
        //算法B实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("学生周六,周日1元/小时");
        }
    }

    //具体算法:临时用户任何时间都是1.5元/小时
    class concreteStrategyC : Strategy
    {
        //算法C实现方法
        public override void AlgorithmInterface()
        {
            Console.WriteLine("临时用户任何时间都是1.5元/小时");
        }
    }

    class Contest
    {
        private string type;
        Strategy strategy;

        public Contest(string Type)
        {
            this.type = Type;
            //利用反射技术生成类的实例
            strategy = (Strategy)Assembly.Load("策略和反射").CreateInstance("策略模式和反射结合." + this.type);
        }

        //上下文接口
        public void ContestInterface()
        {
            strategy.AlgorithmInterface();
        }

    }
}</span>

三种实现方式的比较:

发现代码1.0和代码2.0的主要区别,前者把Switch分支判断放在了客户端,后者利用工厂模式把Switch语句移到了contest中。

显然代码2.0隔离了客户端与具体的算法类,代码有一定优势。

但是,如果我们需要增加一种算法,比如‘教职工免费’,无论代码1.0还是代码2.0,都必须要更改switch代码,这不符合我们的开闭原则。面对同样的需求,当然是改动越小越好。

我们看到代码3.0中用反射技术屏蔽掉了switch语句。这样我们再增加新算法就不必修改context类。从这个角度上说,所有用简单工厂的地方,都可以考虑用反射技术去除选择语句,解除分支语句判断带来的耦合。

七、何时选用策略模式

1、出现有许多相关的类,仅仅是行为有差别的情况,可以使用策略模式来使用多个行为中的一个来配置一个类的方法,实现算法动态切换。

2、出现同一个算法,有很多不同的实现的情况,可以使用策略模式来把这些“不同的实现”实现成为一个算法的类层次。

3、需要封装算法中,与算法相关的数据的情况,可以使用策略模式来避免暴露这些跟算法相关的数据结构。

4、出现抽象一个定义了很多行为的类,并且是通过多个if-else语句来选择这些行为的情况,可以使用策略模式来代替这些条件语句。

综上,策略模式就是用来封装算法的,但在实践中,我们发现可以用它来封装几乎任何类型的规则,只要在分析过程中听到需要再不同时间应用不同的业务规则,就可以考虑使用策略模式处理这种变化的可能性。

八、总结

策略模式属于对象行为型模式,主要针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。

时间: 2024-08-11 03:22:57

[设计模式] 策略模式(Strategy)的相关文章

设计模式 - 策略模式(Strategy Pattern) 具体解释

策略模式(Strategy Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权全部, 禁止转载, 如有须要, 请站内联系. 策略模式: 定义了算法族, 分别封装起来, 让它们之间能够相互替换, 此模式让算法的变化独立于使用算法的客户. 对于父类的子类族须要常常扩展新的功能, 为了使用父类比較灵活的加入子类, 把父类的行为写成接口(interface)的形式; 使用set()方法

设计模式 - 策略模式(Strategy Pattern) 详解

策略模式(Strategy Pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26577879 本文版权所有, 禁止转载, 如有需要, 请站内联系. 策略模式: 定义了算法族, 分别封装起来, 让它们之间可以相互替换, 此模式让算法的变化独立于使用算法的客户. 对于父类的子类族需要经常扩展新的功能, 为了使用父类比较灵活的添加子类, 把父类的行为写成接口(interface)的形式; 使用set()方法,

设计模式---策略模式Strategy(对象行为型)

1. 概述 策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.策略模式让算法独立于使用它的客户而独立变化. 策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理. 2. 应用场景 (1)多个类只区别在表现行为不同,在运行时动态选择具体要执行的行为. (2)需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现. (3)对客户隐藏具体策略(算法)的实现细节,彼此完全独立. 3. 示例 出行旅游:我们可以有几个策略可以考虑:可

说说设计模式~策略模式(Strategy)

策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换.而对于客户端(UI)来说,可以通过IOC再配合工厂模块,实现动态策略的切换,策略模块通常于一个抽象策略对象(interface or abstract class),多个具体策略对象(implement class )和一个调用策略的入口组成. 何时能用到它? 对于UI来说,可能一个功能会有多种实现方式,而且实现方式可能还会有扩展,例如,一个ATM机,它目前支持工行,建行,家行,以后可能又出现了占占银行,而这时,ATM

设计模式--策略模式(strategy)

1.策略模式(strategy ['stræt?d?i]) 我的理解是:方案候选模式 (反正关键就是有很多的候选,哈哈) 看了很多例子,都是在说鸭子的,那个例子很好,然后我就照葫芦画瓢了, 他们生产鸭子,我们就制造人 所以,父类 Person类就出来了 1 public abstract class Person { 2 //唱歌可就不一样了,唱法不同,唱功不同:而且哑巴不能唱歌 3 public void singing(){ 4 System.out.println("我要唱歌")

设计模式-策略模式Strategy以及消灭if else

概述 如果在开发过程中,出现大量的if else或者switch case 语句,如果这些语句块中的代码并不是包含业务逻辑,只是单纯的分流方法,那么,每一个语句块中都是一个算法或者叫策略. 背景 比如在最近项目中遇到的问题.一个二维码字符串解析的方法: 微信的二维码扫描结果包含"WeChat",解析规则是拿着文本到微信服务器解析,返回解析对象. 支付宝二维码扫描结果包含"Alipay",解析规则是使用"->"分割字符串得到解析对象. 最简单

设计模式---策略模式Strategy Pattern

策略模式 定义:定义一系列的算法,把每一个算法封装起来, 并且使它们可相互替换.本模式使得算法可独立于使用它的客户而变化. 问题:有一个鸭子类定义了鸭子的种种行为,包括swim(),quack(),fly(),但是,并不是所有的鸭子都会飞行(fly)或者叫(quack),在这里,我们认为所有的鸭子都会浮在水面上(swim).如何实现各种不同的鸭子的不同的表现. 解决方法:第一个想到的会使继承,在鸭子父类中定义好所有的方法,在实现鸭子子类的过程中,对不满足于具体的鸭子的行为进行覆盖,但是在这种方法

设计模式---策略模式(Strategy Pattern)

先说几个例子,让大家对策略模式有个感性的认识:比如玩RPG游戏时,一个人物可以拥有多种武器,但是攻击时只能使用一把武器,切换武器的过程其实就是一个策略模式的应用. 故事案例:鸭子很多种(活生生的鸭子,橡皮鸭,模型鸭,木头鸭...),共性是可以swim,display(即给别人看),活生生的鸭子可以嘎嘎叫,橡皮鸭子可以吱吱叫,模型鸭可以飞,木头鸭什么特别之处都没有,那我们怎么处理这个问题呢? 思路一:鸭子作为一个抽象类(Duck),然后这些具体的鸭子就继承他,并重新新增一些自己特有的方法.(好像感

设计模式之策略模式(Strategy)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕该功能.如查找.排序等,一种经常使用的方法是硬编码(Hard Coding)在一个类中,如须要提供多种查找算法,能够将这些算法写到一个类中,在该类中提供多个方法,每个方法相应一个详细的查找算法:当然也能够将这些查找算法封装在一个统一的方法中,通过if-else-或者case等条件推断语句来进行选择.