策略模式(Strategy Pattern)
- 策略模式(Strategy Pattern)
- 策略模式概述
- 策略模式结构图
- 策略模式主要包含的角色
- talk is cheap, show you my code
- 总结
策略模式(Strategy Pattern)
策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客户端而变化,从而提高了代码的灵活性和可维护性。
太抽象了
还是举个现实生活中的例子,假如我们现在要设计一个电影院售票系统,我们要给不同的客户提供不同的折扣,比如说:老年人半价,学生票半价,小朋友多少岁之前免票之类的。怎么办?你可能像,我们直接if else不就好了。也许开始的时候是可以实现我们的要求的,但是如果我们现在要增加活动,学生积分抵现,或者看5次免一次票价活动,你想想我们如果要在之前的ifelse里面做改动的话,会导致修改的量很大,而且还非常容易出错。那有没有更好的实现方式呢? 策略模式(Strategy Pattern)
策略模式概述
策略模式结构图
策略模式主要包含的角色
- 策略接口(Strategy):定义了所有支持算法公共操作的接口或抽象类。具体策略类必须实现这个接口中的方法。
public interface Strategy {
void execute();
}
- 具体策略(ConcreteStrategy):实现了 Strategy 接口的具体类。每个具体策略都提供了一种算法的实现方式。
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");
}
}
- 上下文(Context):上下文类拥有一个对策略对象的引用,并提供了设置和获取策略的方法。上下文委托给策略对象来执行具体的算法逻辑。
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
// 策略接口
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的行为可以根据玩家的动作或环境状态来动态调整,这也可以通过策略模式来实现。
策略模式是一个非常有用的设计模式,特别是在需要根据不同情况选择不同算法或行为的时候。它可以帮助我们更好地组织代码,提高系统的灵活性和可维护性。