定义一系列算法,将每个算法封装成独立的对象,并使这些对象可互相替换。这使得在运行时可以动态地选择算法,而不必改变使用算法的客户端代码。策略模式的主要目标是将算法的定义与使用分离,使得客户端可以根据需要灵活地选择和切换不同的算法,而不影响到客户端代码的稳定性。
策略模式的使用场景
- 多种算法实现:
当一个问题有多种算法实现时,可以使用策略模式来将这些算法封装成独立的策略类,使得这些算法可以互相替换,而不影响客户端代码。 - 避免条件判断:
当存在大量的条件语句来选择不同的行为时,可以使用策略模式将这些行为封装成策略类,从而减少条件判断,提高代码的可读性和可维护性。 - 算法变化频繁:
如果系统中的算法经常需要变化,使用策略模式可以方便地新增、修改和替换算法,而不必修改客户端代码。 - 开闭原则支持:
策略模式支持开闭原则,可以在不修改已有代码的情况下扩展系统功能。 - 分层架构:
在分层架构中,策略模式可以用于将业务逻辑与具体的实现分离,使得业务逻辑层和具体实现层解耦。 - 配置灵活性:
当需要根据配置文件或用户输入来选择不同的行为时,策略模式可以提供灵活的配置方式。 - 测试和维护性:
由于策略模式将不同的算法分离成独立的策略类,可以更方便地进行单元测试和维护。
策略模式主要角色
- 策略接口
定义了一组算法的共同接口,具体策略类需要实现这个接口。它通常包含一个或多个抽象方法,用于定义不同算法的行为。 - 具体策略类
实现了策略接口,即具体的算法逻辑。每个具体策略类负责实现一个特定的算法。具体策略类之间是可以相互替换的,客户端代码不需要知道具体算法的实现细节。 - 上下文
持有一个策略对象,并在需要时调用策略的方法。上下文将算法的执行委托给具体的策略对象。上下文也可以包含一些辅助方法,用于操作策略对象。
策略模式的流程
- 客户端创建一个上下文对象,并设置具体的策略对象。
- 当客户端需要执行特定算法时,它调用上下文的方法,上下文会将请求委托给具体策略对象
- 具体策略对象执行算法,并将结果返回给上下文,上下文将结果传递给客户端。
策略模式java代码示例
实现一生鲜市场到点打折活动
策略接口
// 策略接口
public interface DiscountStrategy {double applyDiscount(double originalPrice);
}
策略实现类
public class RegularDiscount implements DiscountStrategy{@Overridepublic double applyDiscount(double originalPrice) {return originalPrice;//原价}
}public class SaleDiscount implements DiscountStrategy {@Overridepublic double applyDiscount(double originalPrice) {return originalPrice*0.8;//8折}
}public class SpecialDiscount implements DiscountStrategy{@Overridepublic double applyDiscount(double originalPrice) {return originalPrice*0.5;//5折}
}
上下文
// 上下文类
public class ShoppingCart{private DiscountStrategy discountStrategy;public void setDiscountStrategy(DiscountStrategy discountStrategy) {this.discountStrategy = discountStrategy;}//获取最新价格public double getPrice(double regularPrice){return discountStrategy.applyDiscount(regularPrice);}}
客户端
public static void main(String[] args) {ShoppingCart cart = new ShoppingCart();double originalPrice = 100.0;double discountedPrice;cart.setDiscountStrategy(new RegularDiscount());discountedPrice = cart.getPrice(originalPrice);System.out.println("8点价格:"+discountedPrice);cart.setDiscountStrategy(new SaleDiscount());discountedPrice = cart.getPrice(originalPrice);System.out.println("9点价格:"+discountedPrice);cart.setDiscountStrategy(new SpecialDiscount());discountedPrice = cart.getPrice(originalPrice);System.out.println("10点价格:"+discountedPrice);
}
输出
8点价格:100.0
9点价格:80.0
10点价格:50.0
策略模式优缺点
优点:
- 灵活性高: 策略模式使得算法可以独立地变化,而不会影响到客户端代码。可以随时切换或扩展算法,而无需修改客户端。
- 可维护性好: 每个具体策略类都具备清晰的职责,使得代码更加模块化和可读。新增或修改算法时,只需修改相应的策略类,不影响其他部分
- 遵循开闭原则: 策略模式支持开闭原则,可以在不修改已有代码的情况下添加新的策略类
- 消除条件判断: 策略模式可以避免大量的条件判断,将不同的行为封装到不同的策略类中,使得代码更加简洁
- 可测试性强: 每个策略类都是相对独立的,易于进行单元测试。
缺点:
- 类数量增多: 策略模式会引入多个具体策略类,可能导致类的数量增多,增加了代码的复杂度。
- 客户端需要了解策略: 客户端需要了解不同的策略类,并选择适当的策略,这可能在某些情况下增加了客户端的复杂度
- 增加对象数量: 每个策略类都是一个对象,可能会增加系统的对象数量。在某些情况下,可以通过共享策略对象来缓解这个问题
- 上下文类复杂: 上下文类需要持有一个策略对象,并在运行时选择合适的策略。在某些情况下,可能会使上下文类变得复杂