zoukankan      html  css  js  c++  java
  • 算法的封装与切换—策略模式(一)

    俗话说:条条大路通罗马。在很多情况下,实现某个目标的途径不止一条,例如我们在外 出旅游时可以选择多种不同的出行方式,如骑自行车、坐汽车、坐火车或者坐飞机,可根据实际情况(目的地、旅游预算、旅游时间等)来选择一种最适合的出行方 式。在制订旅行计划时,如果目的地较远、时间不多,但不差钱,可以选择坐飞机去旅游;如果目的地虽远、但假期长、且需控制旅游成本时可以选择坐火车或汽 车;如果从健康和环保的角度考虑,而且有足够的毅力,自行车游或者徒步旅游也是个不错的选择,大笑

          在软件开发中,我们也常常会遇到类似的情况,实现某一个功能有多条途径,每一条途径对应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。本章我们将介绍一种为了适应算法灵活性而产生的设计模式——策略模式

     

    24.1 电影票打折方案

          Sunny软件公司为某电影院开发了一套影院售票系统,在该系统中需要为不同类型的用户提供不同的电影票打折方式,具体打折方案如下:

          (1) 学生凭学生证可享受票价8折优惠;

          (2) 年龄在10周岁及以下的儿童可享受每张票减免10元的优惠(原始票价需大于等于20元);

          (3) 影院VIP用户除享受票价半价优惠外还可进行积分,积分累计到一定额度可换取电影院赠送的奖品。

          该系统在将来可能还要根据需要引入新的打折方式。

          为了实现上述电影票打折功能,Sunny软件公司开发人员设计了一个电影票类MovieTicket,其核心代码片段如下所示:

    1. //电影票类  
    2. class MovieTicket  
    3.     private double price; //电影票价格  
    4.     private String type; //电影票类型  
    5.       
    6.     public void setPrice(double price)  
    7.         this.price price;  
    8.      
    9.       
    10.     public void setType(String type)  
    11.         this.type type;  
    12.      
    13.       
    14.     public double getPrice()  
    15.         return this.calculate();  
    16.      
    17.       
    18.          //计算打折之后的票价  
    19.     public double calculate()  
    20.                   //学生票折后票价计算  
    21.         if(this.type.equalsIgnoreCase("student"))  
    22.             System.out.println("学生票:");  
    23.             return this.price 0.8 
    24.          
    25.                   //儿童票折后票价计算  
    26.         else if(this.type.equalsIgnoreCase("children"&& this.price >= 20  
    27.             System.out.println("儿童票:");  
    28.             return this.price 10 
    29.          
    30.                   //VIP票折后票价计算  
    31.         else if(this.type.equalsIgnoreCase("vip"))  
    32.             System.out.println("VIP票:");  
    33.             System.out.println("增加积分!");  
    34.             return this.price 0.5 
    35.          
    36.         else  
    37.             return this.price; //如果不满足任何打折要求,则返回原始票价  
    38.          
    39.      
    40.  

          编写如下客户端测试代码:

    1. class Client  
    2.     public static void main(String args[])  
    3.         MovieTicket mt new MovieTicket();  
    4.         double originalPrice 60.0//原始票价  
    5.         double currentPrice; //折后价  
    6.           
    7.         mt.setPrice(originalPrice);  
    8.         System.out.println("原始价为:" originalPrice);  
    9.         System.out.println("---------------------------------");  
    10.               
    11.         mt.setType("student"); //学生票  
    12.         currentPrice mt.getPrice();  
    13.         System.out.println("折后价为:" currentPrice);  
    14.         System.out.println("---------------------------------");  
    15.           
    16.         mt.setType("children"); //儿童票  
    17.         currentPrice mt.getPrice();  
    18.         System.out.println("折后价为:" currentPrice);  
    19.      
    20.  

          编译并运行程序,输出结果如下所示:

    原始价为:60.0

    ---------------------------------

    学生票:

    折后价为:48.0

    ---------------------------------

    儿童票:

    折后价为:50.0

          通过MovieTicket类实现了电影票的折后价计算,该方案解决了电影票打折问题,每一种打折方式都可以称为一种打折算法,更换打折方式只需修改客户端代码中的参数,无须修改已有源代码,但该方案并不是一个完美的解决方案,它至少存在如下三个问题:

          (1) MovieTicket类的calculate()方法非常庞大,它包含各种打折算法的实现代码,在代码中出现了较长的if…else…语句,不利于测试和维护

          (2) 加新的打折算法或者对原有打折算法进行修改时必须修改MovieTicket类的源代码,违反了“开闭原则”,系统的灵活性和可扩展性较差。

          (3) 法的复用性差,如果在另一个系统(如商场销售管理系统)中需要重用某些打折算法,只能通过对源代码进行复制粘贴来重用,无法单独重用其中的某个或某些算法(重用较为麻烦)。

          如何解决这三个问题?导致产生这些问题的主要原因在于MovieTicket类职责过重,它将各种打折算法都定义在一个类中,这既不便于算法的重用,也不便于算法的扩展。因此我们需要对MovieTicket类进行重构,将原本庞大的MovieTicket类的职责进行分解,将算法的定义和使用分离,这就是策略模式所要解决的问题,下面将进入策略模式的学习。

    【作者:刘伟 http://blog.csdn.net/lovelion

  • 相关阅读:
    spark streaming 概述
    spark sql 的性能调优
    LeetCode 106. Construct Binary Tree from Inorder and Postorder Traversal (用中序和后序树遍历来建立二叉树)
    LeetCode 105. Construct Binary Tree from Preorder and Inorder Traversal (用先序和中序树遍历来建立二叉树)
    LeetCode 90. Subsets II (子集合之二)
    LeetCode 88. Merge Sorted Array(合并有序数组)
    LeetCode 81. Search in Rotated Sorted Array II(在旋转有序序列中搜索之二)
    LeetCode 80. Remove Duplicates from Sorted Array II (从有序序列里移除重复项之二)
    LeetCode 79. Word Search(单词搜索)
    LeetCode 78. Subsets(子集合)
  • 原文地址:https://www.cnblogs.com/luckForever/p/7254753.html
Copyright © 2011-2022 走看看