介绍
Java策略模式(Strategy Pattern)是一种行为设计模式,它允许再运行时动态选择算法的行为.策略模式通过将算法封装在可互换的策略对象中,使得客户端代码能够轻松地切换算法,而无需修改原始代码.在策略模式中,每个算法都被实现为一个单独的策略类,这些策略类都实现了相同的接口,从而允许它们在运行时互相替换.
在Java中,可以使用接口或抽象类来定义策略接口.然后对于每个算法,都可以创建一个具体的实现类来实现这个接口.客户端代码可以通过将不同的策略对象传递给上下文对象来选择不同的算法.
Java策略模式通常包括以下三种角色:
- Context(上下文):是策略模式中的核心类,用来管理具体策略实现类的创建,配置和执行,以及在运行时动态地选择具体的策略实现类.
- Strategy(策略):是一个接口或抽象类,定义了策略实现类的通用方法和属性,具体策略实现类必须实现这些方法和属性.
- ConcreteStrategy(具体策略):是策略接口的实现类,根据具体业务需求实现了策略接口定义的方法和属性.可以又多个具体策略实现类,Context类在运行时根据需要动态地选择具体的策略实现类.
实现
支付策略接口(Strategy)
public interface PaymentStrategy {
/**
* 支付
*
* @param amount
*/
void pay(double amount);
}
微信支付和支付宝支付(ConcreteStrategy)
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 + "元");
}
}
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 + "元");
}
}
购物车类(Context)
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());
}
}
商品类
@Data
public class Item {
private String name;
private double price;
public Item(String name, double price) {
this.name = name;
this.price = price;
}
}
测试
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();
}
}
上面代码演示了一个简单的策略模式实现.我们定义了一个PaymentStrategy接口,它表示所有支付方式的共同操作.我们还定义了两个实现该接口的具体类AliPayment和WechatPayment,它们分别表示使用支付宝和微信支付的操作.我们还定义了一个ShoppingCart类,该类使用PaymentStrategy接口来表示支付方式,并根据需要切换实际的支付方式.
在我们的Demo类中,我们创建了一个ShoppingCart对象,并添加了两个Item对象,我们然后选择使用AliPayment进行支付,并调用pay()方法.我们接下来又选择使用WechatPayment进行支付,并再次调用pay()方法.
这样,我们就可以轻松地在不同的支付方式之间进行切换,并根据需要添加新的支付方式.
总结
优点
- 容易扩展和维护:通过定义一个抽象的策略接口,可以方便地增加新的策略实现类,而不需要修改现有代码
- 易于替换算法:在运行时可以动态地切换算法实现,无需修改客户端代码
- 降低了耦合度:客户端只需要知道策略接口即可,不需要知道具体的策略实现类
- 提高了复用性:不同的策略实现类可以在多个场景下复用
缺点
- 增加了类的数量:为每个具体策略都定义了一个实现类,可能会增加类的数量.
- 客户端必须知道策略接口:客户端需要知道具体的策略接口,才能正确使用策略实现类.
- 运行时开销较大:在运行时,需要根据不同的策略实现类进行判断和选择,会带来一定的开销
应用场景
- 有多个相似的类,只有行为有差异的情况下,可以考虑使用策略模式.
- 需要在运行时动态切换算法的情况下,可以使用策略模式.
- 一个系统需要在不同时间应用不同的业务规则情况下,可以使用策略模式
- 在一个系统中,有许多类需要根据某种规则进行排序,查找等操作的情况下,可以使用策略模式.