1.1 需求背景

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

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

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

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

该系统在将来还可能会根据需求引入更多的打折方案。  

1.2 初始设计

  M公司的开发人员为了实现上述需求,设计了一个电影票类MovieTicket,其核心代码片段如下:

    public class MovieTicket{public double Price{get;set;}public string Type { private get; set; }// 计算打折之后的票价public double Calculate(){// 学生票折后票价计算if (this.Type.Equals("student", StringComparison.OrdinalIgnoreCase)){Console.WriteLine("学生票:");return this.Price * 0.8;}// 儿童票折后票价计算else if (this.Type.Equals("children", StringComparison.OrdinalIgnoreCase)){Console.WriteLine("儿童票:");return this.Price - 10;}// VIP票折后票价计算else if (this.Type.Equals("vip", StringComparison.OrdinalIgnoreCase)){Console.WriteLine("VIP票:");Console.WriteLine("增加积分!");return this.Price * 0.5;}else{return this.Price; // 不满足任何条件则原价出售}}}

  客户端调用代码如下:

    public static void Main(){MovieTicket mt = new MovieTicket();double originalPrice = 60.0;    // 原始票价double currentPrice;            // 折后票价mt.Price = originalPrice;Console.WriteLine("原始票价:{0}", originalPrice);Console.WriteLine("----------------------------------------");mt.Type = "student";currentPrice = mt.Calculate();Console.WriteLine("折后票价:{0}", currentPrice);Console.WriteLine("----------------------------------------");mt.Type = "children";currentPrice = mt.Calculate();Console.WriteLine("折后票价:{0}", currentPrice);Console.WriteLine("----------------------------------------");}

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

  (1)MovieTicket类的Calculate()方法非常庞大,太长的if-else语句,不利于测试与维护。

  (2)增加新的打折算法或修改原有打折算法都必须修改MovieTicket类源代码,违反了开闭原则。

  (3)打折算法的复用性比较差,无法在其他系统(例如商场销售管理系统)中进行重用。

  如何解决这3个问题,M公司开发人员决定对MovieTicket类进行重构,将其职责分离,并将打折算法的定义和使用相分离,这也是策略模式所需要解决的问题。

二、策略模式概述

2.1 策略模式简介

  策略模式的主要目的主要是将算法的定义和使用分开,也就是将算法的行为和环境分开,将算法的定义放在专门的策略类中,每一个策略类封装一个实现算法。而使用算法的环境中针对抽象策略编程,而不是针对实现编程,符合依赖倒置原则。

策略(Strategy)模式:定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化。它也被成为政策模式,是一种行为型模式。  

2.2 策略模式结构

  策略模式结构并不复杂,如下图所示:

  策略模式包含以下3个角色:

  (1)Context(环境类):负责使用算法策略,其中维持了一个抽象策略类的引用实例。

  (2)Strategy(抽象策略类):所有策略类的父类,为所支持的策略算法声明了抽象方法。=> 既可以是抽象类也可以是接口

  (3)ConcreteStrategy(具体策略类):实现了在抽象策略类中声明的方法。

三、重构电影票打折方案的设计

3.1 重构后的设计

  为了实现打折算法的复用以及未来的可扩展性,M公司开发人员使用策略模式来重构,其结构如下图所示:

  其中,MovieTicket充当Context环境类,Discount充当抽象策略角色,而StudentDiscount、VIPDiscount和ChildrenDiscount则充当ConcreteStrategy具体策略角色。

3.2 具体代码实现

  (1)Context 环境类:MovieTicket

    /// <summary>/// 环境类:电影票MovieTicket/// </summary>public class MovieTicket{private double _price;private IDiscount _discount;public double Price{get{return _discount.Calculate(_price);}set{_price = value;}}public IDiscount Discount{set{_discount = value;}}}

  (2)Strategy 抽象策略类:IDiscount

     /// <summary>/// 抽象策略类:折扣Discount/// </summary>public interface IDiscount{double Calculate(double price);}

  (3)ConcreteStrategy 具体策略类:StudentStrategy, VIPStrategy 和 ChildrenStrategy

    /// <summary>/// 具体策略类:学生票折扣StudentDiscount/// </summary>public class StudentDiscount : IDiscount{public double Calculate(double price){Console.WriteLine("学生票:");return price * 0.8;}}/// <summary>/// 具体策略类:VIP会员票VIPDiscount/// </summary>public class VIPDiscount : IDiscount{public double Calculate(double price){Console.WriteLine("VIP票:");Console.WriteLine("增加积分!");return price * 0.5;}}/// <summary>/// 具体策略类:儿童票折扣ChildrenDiscount/// </summary>public class ChildrenDiscount : IDiscount{public double Calculate(double price){Console.WriteLine("儿童票:");return price - 10;}}

  (4)客户端调用:

    public class Program{public static void Main(string[] args){MovieTicket mt = new MovieTicket();double originalPrice = 60.0;double currentPrice = originalPrice;mt.Price = originalPrice;Console.WriteLine("原始票价:{0}", originalPrice);Console.WriteLine("----------------------------------------");IDiscount discount = AppConfigHelper.GetStrategyInstance() as IDiscount;if (discount != null){mt.Discount = discount;currentPrice = mt.Price;}Console.WriteLine("折后票价:{0}", currentPrice);Console.ReadKey();}}

  其中,具体的策略被配置在了配置文件中,以此来提高系统灵活性和可扩展性:

<?xml version="1.0" encoding="utf-8" ?>
<configuration><appSettings><add key="DiscountStrategy" value="Manulife.ChengDu.DesignPattern.Strategy.VIPDiscount, Manulife.ChengDu.DesignPattern.Strategy" /></appSettings>
</configuration>

  AppConfigHelper类主要用于读取配置文件,并反射生成具体策略实例,其具体代码如下,这里不再赘述:

 View Code

  编译运行后的结果如下图所示:

  

  如果需要切换策略,例如从VIP改为儿童票,只需修改配置文件:

<?xml version="1.0" encoding="utf-8" ?>
<configuration><appSettings><add key="DiscountStrategy" value="Manulife.ChengDu.DesignPattern.Strategy.ChildrenDiscount, Manulife.ChengDu.DesignPattern.Strategy" /></appSettings>
</configuration>

  重新运行客户端程序,得到如下图所示的结果:

  

  如果后期需要增加新的打折方式,原有代码均无需修改,只需要新增一个折扣策略类即可,然后修改一下配置文件,完全符合开闭原则。

四、策略模式总结

4.1 主要优点

  (1)提供了对开闭原则的完美支持,用户可以在不修改原有系统的基础上选择具体算法或行为,也可以灵活地增加新的算法或行为。

  (2)避免了多重的if-else条件选择语句,利于系统的维护。

  (3)提供了一种算法的复用机制,不同的环境类可以方便地复用这些策略类。

4.2 主要缺点

  (1)客户端需要知道所有的策略类,并自行决定使用哪一个策略 => 只适用于客户端了解所有策略算法的情况

  (2)将造成系统产生很多的具体策略类,任何细小的变化都将导致系统要增加一个具体策略类 => 类的个数也许会超出预期

  (3)无法在客户端同时使用多个策略类 => 客户端每次只能使用一个策略类

4.3 应用场景

  (1)如果一个系统要动态地在几种算法之间选择其中一种 => 那就快用策略模式吧骚年!

  (2)如果有难以维护的多重if-else条件选择语句是为了实现对象的行为 => 那就快用策略模式吧骚年!

  (3)不希望客户知道复杂的与算法有关的数据结构,可以将其封装到策略中 => 提高算法的保密性和安全性!

参考资料

  

  刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

出处:http://www.cnblogs.com/edisonchou/p/7295164.html

转载于:https://www.cnblogs.com/yyxq/p/9778247.html

JAVA设计模式-策略模式相关推荐

  1. Java设计模式-策略模式作业

    Java设计模式-策略模式作业,所有类和接口均在一个package内 文章目录 前言 一.作业内容 二.具体实现 1.类图 2.Strategy接口 3.PreCopyStrategy类 4.Post ...

  2. java设计模式---策略模式

    1,什么是策略模式? 策略模式,又叫算法簇模式,就是定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户. 2,策略模式有什么好处? 策略模式的好处在于你可以动态的改变对象 ...

  3. Java设计模式--策略模式

    策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合 策略模式就是用来封装算法的, ...

  4. 小故事说JAVA设计模式-策略模式【Strategy Pattern】

    # 弄清概念 策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化 # 策略模式 ...

  5. Java设计模式-策略模式(Strategy)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.策略模式 二.策略模式示例代码 1.支付策略 2.具体支付策略实现 3.策略执行对象 4.测试 总结 前言 本篇介 ...

  6. Java设计模式——策略模式(解决满屏的if/else)

    一.业务场景 项目需要对接支付系统,根据不同客户类型会有不同的支付方式,比如:支付宝.微信.银联.云闪付等等其他第三方支付平台,这个时候策略模式就大展身手了. 传统的if/else/switch 等等 ...

  7. Java设计模式----策略模式(Strategy)

    1.  策略模式: 策略模式,也称为政策模式,定义如下: 定义一组算法,将每个算法都封装起来,使他们可以相互转化 2.  策略模式的原理是面向对象的继承和多态.策略模式的3个角色 a. Strateg ...

  8. Java设计模式策略模式(附实例代码)每天一学设计模式

    1.策略模式(Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换.策略模式让算法可以独立于使用它的客户而变化. (1)Context(环境类):环境类是使用 ...

  9. Java设计模式-策略模式(一)

    一.策略模式是什么? 策略模式是指有一定行动内容的相对稳定的策略名称.策略模式在古代中又称"计策",简称"计",如<汉书·高帝纪上>:"汉 ...

最新文章

  1. python运维脚本部署jdk_Jenkins自动执行Python脚本,并输出测试报告
  2. ubuntu中设置mysql的字符集
  3. 【STM32】窗口看门狗 WWDG 实验代码详解
  4. Linux系统中解压缩指令汇总
  5. 灯亮怎么办_车辆隔音效果不好怎么办?
  6. 云小课 | 不了解EIP带宽计费规则?看这里!
  7. Quartz学习总结(2)——定时任务框架Quartz详解
  8. Java提高班(五)深入理解BIO、NIO、AIO
  9. 级联MobileNet-V2实现CelebA人脸关键点检测(附训练源码)
  10. matlab简单分析矩阵乘法——一阶行向量乘一阶列向量
  11. 内江计算机职业学校有哪些,内江第二计算机职业中学有哪些专业
  12. ubuntua安装chrome_Ubuntu 16.04下安装64位谷歌Chrome浏览器
  13. mysql实时监控工具
  14. 数学作图工具_数学趣览X 曾让古希腊人犯怵的三大几何作图难题
  15. pdf去除签名_扫描全能王一键识别图片/PDF/文档/文本文字随意转换
  16. ps 改变图片中的文字
  17. SAP中采购收货冲销和退货适用情形简析
  18. 让数码管比段生成器去见鬼吧
  19. 2017 php 免费空间,免费空间免费php空间
  20. Android 模拟返回键、菜单键、主页键

热门文章

  1. LINUX-Shell第一课
  2. 【基础部分】之apache配置与应用
  3. Axel与Wget下载工具
  4. 为什么放弃治疗_百度百科
  5. 阿里云云服务器更新GCC是提示错误解决方案
  6. window.showModalDialog用法介绍
  7. ip地址详解,ip地址各种写法的意义,私有局域网搭建(IPv4)
  8. C#跑马灯,图片滚动,后台获取图片地址。动态绑定图片,imag显示文字
  9. 《云计算揭秘企业实施云计算的核心问题》——3.5节中小型企业
  10. Android第二十五期 - 猜歌小游戏