• [.net 面向对象程序设计深入](26)实战设计模式——策略模式 Strategy (行为型)


    [.net 面向对象程序设计深入](26)实战设计模式——策略模式 Strategy (行为型)

    1,策略模式定义

    策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

    策略模式的组成: 

    —抽象策略角色: 策略类,通常由一个接口或者抽象类实现。 
    —具体策略角色:包装了相关的算法和行为。 
    —环境角色:持有一个策略类的引用,最终给客户端调用。 

    2,策略模式适场景

     (1)多个相关的类中,仅行为不同,即一个系统中需要在几个不同的算法中选择时。比如中出行中,我们选择交通方式火车、飞机、自行车、汽车等。

    (2)一个算法的不同变体时。比如一个收取暖费的算法,不同的收费方式如按房屋面积、按供热焦耳量、按面积和热量混合法等 。

    (3)不想暴露算法给使用者。比如,有一个复杂算法或算法中有相对应的数据结构不想让使用者知道。

    (4)一个行为中有多个条件时。比如,有多个条件语句,而且实现比较复杂或比较长时,使用策略模式,除了结构清晰外,维护某一分支也比较方便。

    3,策略模式优点 

    (1)抽象策略类和具体策略角色为环境类定义了一系列可以重用的算法或行为,并且继承有助于取出共用部分的算法。

    (2)提供了可以替换继承关系的办法。可以创建一个环境类的子类,里面封装不同的行为,通过环境类来驱动策略。但这样也会导致环境类中的行为包含了具体实现,使用程序难以理解,难以维护。

    (3)消除了复杂的IF..ELSE。含有许多复杂条件语句的代码可以使用策略模式来使逻辑更加清晰,易于维护。

    (4)实了具有相同类型的多个行业的切换。让用户在多个策略中切换行为。

    4,策略模式缺点

    (1)需要事先知道所有策略类行为有何不同,才能让用户很好的选择。容易向使用者暴露策略中的各个行为。

    (2)环境类和策略类之间产生通信开销。

    (3)需要创建很多策略类。后面会说到享元模式,一定程度上减少类。

    5,策略模式应用

    (1)华山论剑

          还是以熟悉的华山论剑为例,比赛方式(也就是三个具体策略类)有“比外功、比内功、比招式”,场景为“华山”(也就是场景类HuaShan),开始比赛了,主持人事先知道这几种比赛方式(也就是具体策略类),主持人(也就是具体使用者)让依次以这几种方式进行。

          先看一下UML类图(在VS中使用类图,可以参考我前面的文章:在Visual Studio 2013/2015中设计UML类图

        

    下面是具体代码:

     抽象策略类 LunJian

    public abstract class LunJian
    {
        public abstract void BiSai();    
    }

    具体策略类 WaiGong NeiGong ZhaoShi

    public class WaiGong : LunJian
    {
        public override void BiSai()
        {
            Console.WriteLine("外功比试开始了!");
        }
    }
    public class NeiGong : LunJian
    {
        public override void BiSai()
        {    
            Console.WriteLine("内功比试开始了!");
        }
    }
    public class ZhaoShi : LunJian
    {
        public override void BiSai()
        {
            Console.WriteLine("招式比试开始了!");
        }
    }

    场景类(也就是策略上下文 ) HuaShan

    public class HuaShan
    {
         LunJian lunJian=null;
    
        public void SetLunJian(LunJian lunJian)
        {
            this.lunJian = lunJian;
        }
    
        public void BiShi()
        {
            this.lunJian.BiSai();
        }
    }

    使用者,就是控制台应用程序

    class Program
        {
            static void Main(string[] args)
            {
                HuaShan huanShan = new HuaShan();
    
                huanShan.SetLunJian(new WaiGong());
                huanShan.BiShi();
               
                huanShan.SetLunJian(new NeiGong());
                huanShan.BiShi();
    
                huanShan.SetLunJian(new ZhaoShi());
                huanShan.BiShi();
    
                Console.ReadLine();
            }
        }

    依次给出三种比试方式策略,运行结果如下:

    (2)华山论剑升级版

    上面的示例比较简单,假如我们比试开始的时候,还需要点名两个比赛选手,这就需要在具体策略类的方法中增加参数。我们增加BiShi()方法参数,改进后代码如下:

      抽象策略类 LunJian

    public abstract class LunJian
    {
        public abstract void BiSai(string player1,string player2);
        
    }

      具体策略类 WaiGong NeiGong ZhaoShi

    public class WaiGong : LunJian
    {
        public override void BiSai(string player1,string player2)
        {
            Console.WriteLine("外功比试开始了!"+string.Format(" {0} 和 {1} 出场",player1,player2));
        }
    }
    public class NeiGong : LunJian
    {
        public override void BiSai(string player1, string player2)
        {    
            Console.WriteLine("内功比试开始了!" + string.Format(" {0} 和 {1} 出场", player1, player2));
        }
    }
    public class ZhaoShi : LunJian
    {
        public override void BiSai(string player1, string player2)
        {
            Console.WriteLine("招式比试开始了!" + string.Format(" {0} 和 {1} 出场", player1, player2));
        }
    }

      场景类(也就是策略上下文 ) HuaShan

    public class HuaShan
    {
         LunJian lunJian=null;
    
        public void SetLunJian(LunJian lunJian)
        {
            this.lunJian = lunJian;
        }
    
        public void BiShi(string player1,string player2)
        {
            this.lunJian.BiSai(player1,player2);
        }
    }

      使用者,就是控制台应用程序

        class Program
        {
            static void Main(string[] args)
            {
                HuaShan huanShan = new HuaShan();
    
                huanShan.SetLunJian(new WaiGong());
                huanShan.BiShi("黄药师","欧阳锋");
               
                huanShan.SetLunJian(new NeiGong());
                huanShan.BiShi("洪七公","一灯大师");
    
                huanShan.SetLunJian(new ZhaoShi());
                huanShan.BiShi("欧阳锋","洪七公");
    
                Console.ReadLine();
            }
        }

    运行结果:

    华山论剑的业务肯定比这个要复杂,上面的出场人不同,比赛方式不同,甚至还其他不同的规则出现。

    如果我们不使用策略模式,而通过传统的if...else来写,不但要写很长的代码,还需要条件语句多次嵌套。

    最主要的是代码的可读性较差,而且难以再解。

    6,总结 

    (1)策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。策略模式通常把一个系列的算法封装到一系列的策略类里面,作为一个抽象策略类的子类。用一句话来说,就是“准备一组算法,并将每一个算法封装起来,使得它们可以互换”。
    (2)在策略模式中,应当由客户端自己决定在什么情况下使用什么具体策略角色。

    (3)策略模式仅仅封装算法,提供新算法插入到已有系统中,以及老算法从系统中“退休”的方便,策略模式并不决定在何时使用何种算法,算法的选择由客户端来决定。这在一定程度上提高了系统的灵活性,但是客户端需要理解所有具体策略类之间的区别,以便选择合适的算法,这也是策略模式的缺点之一,在一定程度上增加了客户端的使用难度。

    7.实例源代码

    https://github.com/yubinfeng/BlogExamples.git

    ==============================================================================================

    返回目录

    <如果对你有帮助,记得点一下推荐哦,如有有不明白或错误之处,请多交流>

    <对本系列文章阅读有困难的朋友,请先看 《.net 面向对象编程基础》 和 《.net 面向对象程序设计进阶》 >

    <转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>

    .NET 技术交流群:467189533 H.NET 技术交流群

    ==============================================================================================

  • 相关阅读:
    leetcode题解:Search in Rotated Sorted Array(旋转排序数组查找)
    leetcode 题解:Remove Duplicates from Sorted Array II(已排序数组去三次及以上重复元素)
    leetcode 题解:Remove Duplicates from Sorted Array(已排序数组去重)
    leetcode题解:Tree Level Order Traversal II (二叉树的层序遍历 2)
    leetcode 题解:Binary Tree Level Order Traversal (二叉树的层序遍历)
    c++ STL:队列queue、优先队列priority queue 的使用
    leetcode题解:Binary Tree Postorder Traversal (二叉树的后序遍历)
    算术表达式解析(第三版)词法分析版
    经典算法:牛顿迭代法求平方根
    进入游戏行业1年的总结
  • 原文地址:https://www.cnblogs.com/yubinfeng/p/6534805.html
Copyright © 2020-2023  润新知