策略模式
策略模式(Strategy Pattern)是一种行为设计模式,它定义了一系列算法,将每一个算法封装起来,使它们可以互相替换。策略模式使得算法可以独立于使用它的客户端变化。策略模式的主要目的是分离算法,使得算法独立于客户端而变化。
原理
策略模式包含以下几个角色:
- 策略接口(Strategy):定义所有支持的算法的公共接口。通常使用一个抽象类或接口来定义。
- 具体策略类(ConcreteStrategy):实现 Strategy 接口的具体算法。
- 上下文类(Context):持有一个策略类的引用,并用于调用具体策略类中定义的算法。
- 客户端代码(Client):使用 Context 来执行策略,并根据需求选择不同的策略实现。
实现
1、定义策略接口(Strategy):
public interface PricingStrategy {
double calculatePrice(double price);
}
2、实现具体策略类(ConcreteStrategy):
public class RegularPricingStrategy implements PricingStrategy {
@Override
public double calculatePrice(double price) {
return price;
}
}
public class DiscountPricingStrategy implements PricingStrategy {
private double discount;
public DiscountPricingStrategy(double discount) {
this.discount = discount;
}
@Override
public double calculatePrice(double price) {
return price * (1 - discount);
}
}
public class PremiumPricingStrategy implements PricingStrategy {
private double premium;
public PremiumPricingStrategy(double premium) {
this.premium = premium;
}
@Override
public double calculatePrice(double price) {
return price + premium;
}
}
3、定义上下文类(Context):
public class PriceCalculator {
private PricingStrategy strategy;
public void setStrategy(PricingStrategy strategy) {
this.strategy = strategy;
}
public double calculate(double price) {
if (strategy == null) {
throw new IllegalStateException("Pricing strategy not set");
}
return strategy.calculatePrice(price);
}
}
4、测试
public class StrategyPatternDemo {
public static void main(String[] args) {
PriceCalculator priceCalculator = new PriceCalculator();
// 使用 RegularPricingStrategy
priceCalculator.setStrategy(new RegularPricingStrategy());
double regularPrice = priceCalculator.calculate(100);
System.out.println("Regular Price: " + regularPrice);
// 使用 DiscountPricingStrategy
priceCalculator.setStrategy(new DiscountPricingStrategy(0.2));
double discountPrice = priceCalculator.calculate(100);
System.out.println("Discount Price: " + discountPrice);
// 使用 PremiumPricingStrategy
priceCalculator.setStrategy(new PremiumPricingStrategy(30));
double premiumPrice = priceCalculator.calculate(100);
System.out.println("Premium Price: " + premiumPrice);
}
}
5、结果
Regular Price: 100.0
Discount Price: 80.0
Premium Price: 130.0
分析
- PricingStrategy接口:定义一个算法接口 calculatePrice,其不同实现代表不同的价格计算方式。
- 具体策略类:RegularPricingStrategy、DiscountPricingStrategy、PremiumPricingStrategy 实现了 PricingStrategy 接口,分别执行常规价格、折扣价格和溢价价格的计算。
- 上下文类:PriceCalculator 维护一个 PricingStrategy 类型的引用,通过 setStrategy 方法动态设置所需的策略,并通过 calculate 方法使用当前策略计算价格。
- 客户端代码:在 main 方法中,通过设置不同的策略,使用 PriceCalculator 对象来计算价格。这样,如果要添加或者更改计算策略,只需要创建新的 ConcreteStrategy 并在上下文中设置即可,符合开闭原则。
业务实现
实际的业务场景很难让我们提前预知要用哪种策略
简单来写的话往往是这样的
1、实现
public class StrategyPatternFactory {
public static PriceCalculator getPriceCalculator(String pct) {
PriceCalculator priceCalculator = new PriceCalculator();
switch (pct){
case "Regular":
priceCalculator.setStrategy(new RegularPricingStrategy());
break;
case "Discount":
priceCalculator.setStrategy(new DiscountPricingStrategy(0.2));
break;
case "Premium":
priceCalculator.setStrategy(new PremiumPricingStrategy(30));
break;
default:
throw new RuntimeException("不存在策略"+pct);
}
return priceCalculator;
}
}
2、测试
public class StrategyPatternDemo {
public static void main(String[] args) {
PriceCalculator priceCalculator = StrategyPatternFactory.getPriceCalculator("Regular");
double regularPrice = priceCalculator.calculate(100);
System.out.println("Price: " + regularPrice);
}
}
3、结果
Regular Price: 100.0
这样子可以满足业务的需求了,但是每次新来一种策略,就要在原有代码上新增
public class StrategyPatternFactory {
public static PriceCalculator getPriceCalculator(String pct) {
PriceCalculator priceCalculator = new PriceCalculator();
switch (pct) {
case "Regular":
priceCalculator.setStrategy(new RegularPricingStrategy());
break;
case "Discount":
priceCalculator.setStrategy(new DiscountPricingStrategy(0.2));
break;
case "Premium":
priceCalculator.setStrategy(new PremiumPricingStrategy(30));
break;
case "新增":
priceCalculator.setStrategy(new AddPricingStrategy());
break;
default:
throw new RuntimeException("不存在策略" + pct);
}
return priceCalculator;
}
}
在运行稳定的代码进行改动是不明智的 ,可以进一步进行增强
增强
可以利用spring的特性结合工程模式,实现解耦
1、定义策略接口(Strategy):
public interface PricingStrategy {
double calculatePrice(double price);
}
2、定义抽象策略类(AbstractStrategy):
public abstract class AbstractPricingStrategy implements PricingStrategy, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
PricingStrategyFactory.setPricingStrategy(getType(), this);
}
public abstract String getType();
}
3、实现具体策略
@Service
public class RegularPricingStrategy extends AbstractPricingStrategy {
@Override
public double calculatePrice(double price) {
return price;
}
@Override
public String getType() {
return "Regular";
}
}
@Service
public class DiscountPricingStrategy extends AbstractPricingStrategy {
private double discount = 0.2;
@Override
public double calculatePrice(double price) {
return price * (1 - discount);
}
@Override
public String getType() {
return "Discount";
}
}
public class PremiumPricingStrategy extends AbstractPricingStrategy {
private double premium = 30;
@Override
public double calculatePrice(double price) {
return price + premium;
}
@Override
public String getType() {
return "Premium";
}
}
4、定义工厂类(factory):
public class StrategyPatternFactory {
private static Map<String, PriceCalculator> map = new HashMap<>();
public static PriceCalculator getPriceCalculator(String pct) {
PriceCalculator priceCalculator = map.get(pct);
if (priceCalculator == null) {
throw new IllegalStateException("Pricing strategy not set");
}
return priceCalculator;
}
public static void setPriceCalculator(String pct, PriceCalculator priceCalculator) {
map.put(pct, priceCalculator);
}
}
5、测试
public static void main(String[] args) {
PricingStrategy regular = PricingStrategyFactory.getPriceCalculator("Regular");
regular.calculatePrice(100);
PricingStrategy discount = PricingStrategyFactory.getPriceCalculator("Discount");
discount.calculatePrice(100);
PricingStrategy premium = PricingStrategyFactory.getPriceCalculator("Premium");
premium.calculatePrice(100);
}
6、结果
Regular Price: 100.0
Discount Price: 80.0
Premium Price: 130.0
以上的增强只是介绍了一下基本增强方案,大家可以根据自己的思维进一步增强,利用更多的设计模式,使得系统更加健壮