电影院售票 - 策略模式(Strategy Pattern)

策略模式(Strategy Pattern)

策略模式(Strategy Pattern)

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户端而变化,从而提高了代码的灵活性和可维护性。

太抽象了

还是举个现实生活中的例子,假如我们现在要设计一个电影院售票系统,我们要给不同的客户提供不同的折扣,比如说:老年人半价,学生票半价,小朋友多少岁之前免票之类的。怎么办?你可能像,我们直接if else不就好了。也许开始的时候是可以实现我们的要求的,但是如果我们现在要增加活动,学生积分抵现,或者看5次免一次票价活动,你想想我们如果要在之前的ifelse里面做改动的话,会导致修改的量很大,而且还非常容易出错。那有没有更好的实现方式呢? 策略模式(Strategy Pattern)

策略模式概述

策略模式结构图

策略模式主要包含的角色

  1. 策略接口(Strategy):定义了所有支持算法公共操作的接口或抽象类。具体策略类必须实现这个接口中的方法。
java 复制代码
public interface Strategy {
    void execute();
}
  1. 具体策略(ConcreteStrategy):实现了 Strategy 接口的具体类。每个具体策略都提供了一种算法的实现方式。
java 复制代码
public class ConcreteStrategyA implements Strategy {
    @Override
    public void execute() {
        System.out.println("strategy A");
    }
}

public class ConcreteStrategyB implements Strategy {
    @Override
    public void execute() {
        System.out.println("strategy B");
    }
}
  1. 上下文(Context):上下文类拥有一个对策略对象的引用,并提供了设置和获取策略的方法。上下文委托给策略对象来执行具体的算法逻辑。
java 复制代码
public class Context {
    private Strategy strategy;

    // 设置策略
    public void setStrategy(Strategy strategy) {
        this.strategy = strategy;
    }

    // 执行策略
    public void executeStrategy() {
        if (strategy != null) {
            strategy.execute();
        } else {
            System.out.println("Strategy not set");
        }
    }
}

talk is cheap, show you my code

java 复制代码
// 策略接口
interface PricingStrategy {
    double calculatePrice(double basePrice);
}
 
// 成人票价策略
class AdultPricingStrategy implements PricingStrategy {
    @Override
    public double calculatePrice(double basePrice) {
        // 假设成人票价没有折扣
        return basePrice;
    }
}
 
// 儿童票价策略
class ChildPricingStrategy implements PricingStrategy {
    @Override
    public double calculatePrice(double basePrice) {
        // 假设儿童票价是半价
        return basePrice / 2;
    }
}
 
// 学生票价策略
class StudentPricingStrategy implements PricingStrategy {
    @Override
    public double calculatePrice(double basePrice) {
        // 假设学生票价有8折优惠
        return basePrice * 0.8;
    }
}
 
// 电影票类
class MovieTicket {
    private String movieName;
    private double basePrice;
    private PricingStrategy pricingStrategy;
 
    public MovieTicket(String movieName, double basePrice, PricingStrategy pricingStrategy) {
        this.movieName = movieName;
        this.basePrice = basePrice;
        this.pricingStrategy = pricingStrategy;
    }
 
    public double getPrice() {
        return pricingStrategy.calculatePrice(basePrice);
    }
 
    @Override
    public String toString() {
        return "MovieTicket{" +
                "movieName='" + movieName + '\'' +
                ", price=" + getPrice() +
                '}';
    }
}
 
// 客户端类
public class CinemaTicketingSystem {
    public static void main(String[] args) {
        double basePrice = 100.0; // 假设基础票价为100元
 
        // 创建不同的票价策略
        PricingStrategy adultStrategy = new AdultPricingStrategy();
        PricingStrategy childStrategy = new ChildPricingStrategy();
        PricingStrategy studentStrategy = new StudentPricingStrategy();
 
        // 创建电影票对象
        MovieTicket adultTicket = new MovieTicket("Inception", basePrice, adultStrategy);
        MovieTicket childTicket = new MovieTicket("Inception", basePrice, childStrategy);
        MovieTicket studentTicket = new MovieTicket("Inception", basePrice, studentStrategy);
 
        // 打印票价
        System.out.println(adultTicket); // MovieTicket{movieName='Inception', price=100.0}
        System.out.println(childTicket);  // MovieTicket{movieName='Inception', price=50.0}
        System.out.println(studentTicket); // MovieTicket{movieName='Inception', price=80.0}
    }
}

在这个例子中,PricingStrategy接口定义了计算票价的方法。AdultPricingStrategy、ChildPricingStrategy和StudentPricingStrategy类分别实现了这个接口,并提供了不同的计算逻辑。MovieTicket类有一个PricingStrategy类型的成员变量,用于存储当前电影票所使用的票价策略。在getPrice方法中,它调用策略对象的calculatePrice方法来计算票价。

总结

策略模式的优点

  • 算法与客户端分离:通过将算法封装在独立的策略类中,使得算法的实现细节对客户端透明。
  • 易于扩展:新增加一种算法只需添加一个新的具体策略类,而不必修改现有的代码。
  • 符合开闭原则:当需要添加新的策略时,只需创建新的策略类,而不需要改变已有的代码。
  • 避免条件语句:使用策略模式可以减少代码中的条件判断语句,提高代码的清晰度和可读性。

策略模式缺点

  • 增加类的数量
  • 客户端需要知道所有的策略
  • 接口定义困难
  • 策略的组合与复用有限
  • 简单场景不建议使用策略模式

策略模式的应用场景

  • 不同支付方式:如现金、信用卡、支付宝等支付方式的选择可以通过策略模式来实现。
  • 排序算法:根据数据量大小选择不同的排序算法(快速排序、插入排序等),也可以用策略模式来管理。
  • 日志记录:不同的日志级别(DEBUG、INFO、ERROR等)可以有不同的处理方式,这些都可以作为策略来实现。
  • 游戏AI:在游戏中,NPC的行为可以根据玩家的动作或环境状态来动态调整,这也可以通过策略模式来实现。

策略模式是一个非常有用的设计模式,特别是在需要根据不同情况选择不同算法或行为的时候。它可以帮助我们更好地组织代码,提高系统的灵活性和可维护性。

相关推荐
Alan CGH3 分钟前
高并发写利器-组提交,我的Spring组件实战
java·后端·spring
苹果酱056721 分钟前
Pytorch机器学习——1 深度学习介绍
java·vue.js·spring boot·mysql·课程设计
马丁•路德•王29 分钟前
Java测试开发平台搭建(八) Jenkins
java·servlet·jenkins
李歘歘36 分钟前
Redis数据库——Redis雪崩、穿透、击穿
java·数据库·redis·mysql·缓存·go
神的孩子都在歌唱1 小时前
你已经分清JAVA中JVM、JDK与JRE的作用和关系了吗?
java·开发语言·jvm
一条小小yu1 小时前
从零开始手写缓存之如何实现固定缓存大小
java·spring·缓存
天之涯上上1 小时前
JAVA开发中 MyBatis XML 映射文件 的作用
xml·java·mybatis
鸿永与2 小时前
『SQLite』常见数据类型(动态类型系统)
java·数据库·sqlite
一弓虽2 小时前
java基础学习——java泛型
java·学习
我真不会起名字啊3 小时前
QtJson数据格式处理详解
java·前端·javascript