2023-04-01  阅读(1)
原文作者:LoveLion 原文地址:https://blog.csdn.net/lovelion/article/details/7818983

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

202304012109150981.png

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

24.1 电影票打折方案

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

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

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

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

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

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

    //电影票类
    class MovieTicket {
    	private double price; //电影票价格
    	private String type; //电影票类型
    	
    	public void setPrice(double price) {
    		this.price = price;
    	}
    	
    	public void setType(String type) {
    		this.type = type;
    	}
    	
    	public double getPrice() {
    		return this.calculate();
    	}
    	
             //计算打折之后的票价
    	public double calculate() {
                      //学生票折后票价计算
    		if(this.type.equalsIgnoreCase("student")) {
    			System.out.println("学生票:");
    		    return this.price * 0.8;
    		}
                      //儿童票折后票价计算
    		else if(this.type.equalsIgnoreCase("children") && this.price >= 20 ) {
    			System.out.println("儿童票:");
    		    return this.price - 10;
    		}
                      //VIP票折后票价计算
    		else if(this.type.equalsIgnoreCase("vip")) {
    			System.out.println("VIP票:");
    		    System.out.println("增加积分!");
    			return this.price * 0.5;
    		}
    		else {
    			return this.price; //如果不满足任何打折要求,则返回原始票价
    		}
    	}
    }

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

    class Client {
    	public static void main(String args[]) {
    		MovieTicket mt = new MovieTicket();
    		double originalPrice = 60.0; //原始票价
    		double currentPrice; //折后价
    		
    		mt.setPrice(originalPrice);
    		System.out.println("原始价为:" + originalPrice);
    		System.out.println("---------------------------------");
    			
    		mt.setType("student"); //学生票
    		currentPrice = mt.getPrice();
    		System.out.println("折后价为:" + currentPrice);
    		System.out.println("---------------------------------");
    		
    		mt.setType("children"); //儿童票
    		currentPrice = mt.getPrice();
    		System.out.println("折后价为:" + currentPrice);
    	}
    }

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

原始价为:60.0

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

学生票:

折后价为:48.0

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

儿童票:

折后价为:50.0

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

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

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

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

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


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文