Java 策略模式:灵活应对业务变化的利器
简介
在软件开发过程中,我们常常会遇到这样的情况:一个系统中的某个行为或算法,在不同的场景下需要有不同的实现方式。例如,电商系统中的促销活动,不同时期可能有不同的折扣策略;游戏中的角色行为,不同角色可能有不同的移动方式。策略模式就是为了解决这类问题而诞生的一种设计模式。它通过将算法的定义和使用分离,使得代码更加灵活、可维护和可扩展。
目录
- 策略模式基础概念
- 使用方法
- 常见实践
- 最佳实践
- 小结
- 参考资料
策略模式基础概念
策略模式定义了一系列算法,将每个算法都封装起来,并且使它们可以相互替换。在策略模式中,有三个主要角色: - 抽象策略(Strategy):定义了一个公共接口,所有具体策略类都必须实现这个接口。这个接口规定了算法的基本行为。 - 具体策略(Concrete Strategy):实现了抽象策略接口,提供了具体的算法实现。 - 上下文(Context):持有一个抽象策略类的引用,通过这个引用调用具体策略类的算法。
使用方法
代码示例
下面我们通过一个简单的示例来演示策略模式的使用。假设我们有一个电商系统,需要根据不同的促销活动计算商品的折扣价格。
- 定义抽象策略接口
public interface DiscountStrategy {
double calculateDiscount(double originalPrice);
}
- 实现具体策略类
- 无折扣策略
public class NoDiscountStrategy implements DiscountStrategy {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice;
}
}
- **打九折策略**
public class TenPercentDiscountStrategy implements DiscountStrategy {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice * 0.9;
}
}
- **满减策略**
public class CashbackDiscountStrategy implements DiscountStrategy {
@Override
public double calculateDiscount(double originalPrice) {
if (originalPrice >= 100) {
return originalPrice - 20;
}
return originalPrice;
}
}
- 定义上下文类
public class ShoppingCart {
private DiscountStrategy discountStrategy;
public ShoppingCart(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public double calculateTotalPrice(double originalPrice) {
return discountStrategy.calculateDiscount(originalPrice);
}
}
- 测试代码
public class Main {
public static void main(String[] args) {
// 使用无折扣策略
ShoppingCart cart1 = new ShoppingCart(new NoDiscountStrategy());
double price1 = cart1.calculateTotalPrice(100);
System.out.println("无折扣价格: " + price1);
// 使用打九折策略
ShoppingCart cart2 = new ShoppingCart(new TenPercentDiscountStrategy());
double price2 = cart2.calculateTotalPrice(100);
System.out.println("九折后价格: " + price2);
// 使用满减策略
ShoppingCart cart3 = new ShoppingCart(new CashbackDiscountStrategy());
double price3 = cart3.calculateTotalPrice(100);
System.out.println("满减后价格: " + price3);
}
}
在这个示例中,DiscountStrategy
是抽象策略接口,NoDiscountStrategy
、TenPercentDiscountStrategy
和 CashbackDiscountStrategy
是具体策略类,ShoppingCart
是上下文类。通过在 ShoppingCart
中传入不同的具体策略对象,我们可以根据不同的促销活动计算商品的折扣价格。
常见实践
替换条件语句
在没有使用策略模式之前,我们可能会使用大量的条件语句(如 if-else
或 switch
)来根据不同的情况选择不同的算法。例如:
public double calculateDiscount(double originalPrice, String discountType) {
if ("noDiscount".equals(discountType)) {
return originalPrice;
} else if ("tenPercentDiscount".equals(discountType)) {
return originalPrice * 0.9;
} else if ("cashbackDiscount".equals(discountType)) {
if (originalPrice >= 100) {
return originalPrice - 20;
}
return originalPrice;
}
return originalPrice;
}
这种方式使得代码难以维护和扩展,当需要添加新的折扣策略时,需要修改这个方法,增加新的条件分支。而使用策略模式,我们只需要添加新的具体策略类,不需要修改上下文类的代码。
代码复用
策略模式可以将不同的算法封装在具体策略类中,这些具体策略类可以在不同的上下文中复用。例如,在一个游戏系统中,不同的角色可能有不同的移动方式(如步行、飞行、跳跃),我们可以将这些移动方式定义为具体策略类,然后在不同的角色类中复用这些策略。
最佳实践
依赖注入
在上下文类中,通过构造函数或 setter 方法注入具体策略对象,这样可以提高代码的灵活性和可测试性。例如:
public class ShoppingCart {
private DiscountStrategy discountStrategy;
// 通过构造函数注入
public ShoppingCart(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
// 通过 setter 方法注入
public void setDiscountStrategy(DiscountStrategy discountStrategy) {
this.discountStrategy = discountStrategy;
}
public double calculateTotalPrice(double originalPrice) {
return discountStrategy.calculateDiscount(originalPrice);
}
}
策略枚举
对于一些简单的策略,可以使用枚举来实现。枚举可以提供一种简洁的方式来定义和管理一组相关的策略。例如:
public enum DiscountEnum implements DiscountStrategy {
NO_DISCOUNT {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice;
}
},
TEN_PERCENT_DISCOUNT {
@Override
public double calculateDiscount(double originalPrice) {
return originalPrice * 0.9;
}
},
CASHBACK_DISCOUNT {
@Override
public double calculateDiscount(double originalPrice) {
if (originalPrice >= 100) {
return originalPrice - 20;
}
return originalPrice;
}
}
}
使用时可以这样:
public class ShoppingCart {
private DiscountStrategy discountStrategy;
public ShoppingCart(DiscountEnum discountEnum) {
this.discountStrategy = discountEnum;
}
public double calculateTotalPrice(double originalPrice) {
return discountStrategy.calculateDiscount(originalPrice);
}
}
策略工厂
当需要根据不同的条件动态创建具体策略对象时,可以使用策略工厂。策略工厂可以封装策略对象的创建逻辑,使得上下文类不需要关心具体策略对象的创建过程。例如:
public class DiscountStrategyFactory {
public static DiscountStrategy getDiscountStrategy(String discountType) {
if ("noDiscount".equals(discountType)) {
return new NoDiscountStrategy();
} else if ("tenPercentDiscount".equals(discountType)) {
return new TenPercentDiscountStrategy();
} else if ("cashbackDiscount".equals(discountType)) {
return new CashbackDiscountStrategy();
}
return new NoDiscountStrategy();
}
}
使用时可以这样:
public class ShoppingCart {
private DiscountStrategy discountStrategy;
public ShoppingCart(String discountType) {
this.discountStrategy = DiscountStrategyFactory.getDiscountStrategy(discountType);
}
public double calculateTotalPrice(double originalPrice) {
return discountStrategy.calculateDiscount(originalPrice);
}
}
小结
策略模式通过将算法的定义和使用分离,使得代码更加灵活、可维护和可扩展。它可以有效替换复杂的条件语句,提高代码的复用性。在实际应用中,我们可以结合依赖注入、策略枚举和策略工厂等最佳实践,进一步优化代码结构,提高系统的性能和可维护性。通过掌握策略模式,我们能够更好地应对业务需求的变化,提高软件开发的效率和质量。
参考资料
- 《设计模式 - 可复用的面向对象软件元素》(Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides 著)
- 《Effective Java》(Joshua Bloch 著)
- 维基百科 - 策略模式