-
策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更加灵活,具有更好的维护性和扩展性。
-
策略模式属于行为型模式
摘要
1. 意图
- 针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
2. 主要解决
- 它将对象和行为分开,将行为定义为一个行为接口和具体的行为实现,说白了策略模式就是用来解决多个if判断的情况的。
3. 何时使用
- 需要在运行时动态地改变对象的行为
- 有多个算法可选,客户端需要根据不同的需要选择不同的算法
- 一个类定义了多种行为,并且这些行为在类的方法中以多个条件语句的形式出现。这时候可以将每种条件分支转化为一个独立的策略
4. 如何解决
- 将这些通用算法抽象出来
5. 关键代码
- 策略接口、具体策略类和环境类
6. 应用实例
- 做一批相机,分配中心需要根据相机的类型去找到不同的工人做相机
- 电商购物的优惠计算
7. 优点
- 松耦合:策略模式将不同的策略封装在独立的类中,与上下文对象解耦,增加了代码的灵活性和可维护性。
- 易于扩展:可以通过添加新的策略类来扩展系统的功能,无需修改现有代码。
- 符合开闭原则:对于新的策略,无需修改上下文对象,只需要实现新的策略接口即可。
8. 缺点
- 类数量增多:每个具体策略都需要一个独立的类,如果策略较多,将导致类的数量增加。
- 上层必须知道所有策略类:上层模块必须知道有哪些策略,并选择合适的策略进行使用,这与迪米特法则是相违背的,我只是想使用了一个策略,我凭什么就要了解这个策略呢?那要你的封装类还有什么 意义?这是原装策略模式的一个缺点。
9. 使用场景
- 有多个相似的类,只有行为有差异的情况下,可以考虑使用策略模式.
- 需要在运行时动态切换算法的情况下,可以使用策略模式.
- 一个系统需要在不同时间应用不同的业务规则情况下,可以使用策略模式
- 在一个系统中,有许多类需要根据某种规则进行排序,查找等操作的情况下,可以使用策略模式.
10. 注意事项
- 如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题,否则日后的系统维护就会成为一个烫手山芋。
实现
Java策略模式通常包括以下三种角色:
- Context(上下文):是策略模式中的核心类,用来管理具体策略实现类的创建,配置和执行,以及在运行时动态地选择具体的策略实现类.
- Strategy(策略):是一个接口或抽象类,定义了策略实现类的通用方法和属性,具体策略实现类必须实现这些方法和属性.
- ConcreteStrategy(具体策略):是策略接口的实现类,根据具体业务需求实现了策略接口定义的方法和属性.可以又多个具体策略实现类,Context类在运行时根据需要动态地选择具体的策略实现类.
范例
1. 支付策略接口(Strategy)
Strategy.java
package com.demo.gof;
public interface PaymentStrategy {
/**
* 支付
*
* @param amount
*/
void pay(double amount);
}
2. 微信支付和支付宝支付策略类(ConcreteStrategy)
WechatPayment.java
package com.demo.gof;
public class WechatPayment implements PaymentStrategy {
private String username;
private String password;
public WechatPayment(String username, String password) {
this.username = username;
this.password = password;
}
/**
* 支付
*
* @param amount
*/
@Override
public void pay(double amount) {
System.out.println("微信支付:" + amount + "元");
}
}
AliPayment.java
package com.demo.gof;
public class AliPayment implements PaymentStrategy{
private String username;
private String password;
public AliPayment(String username, String password) {
this.username = username;
this.password = password;
}
/**
* 支付
*
* @param amount
*/
@Override
public void pay(double amount) {
System.out.println("支付宝支付:" + amount + "元");
}
}
3. 购物车类(Context)
ShoppingCart.java
package com.demo.gof;
public class ShoppingCart {
private List<Item> itemList;
private PaymentStrategy paymentStrategy;
public ShoppingCart() {
itemList = new ArrayList<>();
}
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void addItem(Item item){
itemList.add(item);
}
public void removeItem(Item item){
itemList.remove(item);
}
public double calculateTotal(){
return itemList.stream().mapToDouble(Item::getPrice).sum();
}
public void pay(){
paymentStrategy.pay(calculateTotal());
}
}
4. 商品类
Item.java
package com.demo.gof;
@Data
public class Item {
private String name;
private double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
}
5. 运行执行策略模式
Demo.java
package com.demo.gof;
public class Demo {
public static void main(String[] args) {
ShoppingCart shoppingCart = new ShoppingCart();
Item item1 = new Item("item1",10);
Item item2 = new Item("item2",10);
shoppingCart.addItem(item1);
shoppingCart.addItem(item2);
shoppingCart.setPaymentStrategy(new AliPayment("aliPayUsername","aliPayPassword"));
shoppingCart.pay();
shoppingCart.setPaymentStrategy(new WechatPayment("wechatUsername","wechatPassword"));
shoppingCart.pay();
}
}
编译运行以上 Java 范例,输出结果如下