策略设计模式是行为型设计模式的一种。当存在多种算法去实现某一特定任务,且由客户端在运行时决定具体的实现时,则可以使用策略模式。
策略模式
我们定义多种算法实现并让客户端应用传递参数的方式来指定使用具体的算法。使用 Comparator 参数的 Collections.sort() 方法是策略模式非常好的示例。根据Comperator接口的不同实现,对象可以采用不同算法进行排序。对于下面的示例,将尝试实现一个简单的购物车,其中有两种付款策略,使用信用卡或微信支付。首先,我们会创建一个支付策略接口,并提供一个带金额参数的pay方法。
PaymentStrategy.java
package com.example.strategy;
public interface PaymentStrategy {
public void pay(int amount);
}
创建信用卡/微信支付两种支付方式接口实现。
CreditCardStrategy.java
package com.example.strategy;
public class CreditCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
this.name=nm;
this.cardNumber=ccNum;
this.cvv=cvv;
this.dateOfExpiry=expiryDate;
}
@Override
public void pay(int amount) {
System.out.println(amount +" paid with credit/debit card");
}
}
PaypalStrategy.java
package com.example.strategy;
public class PaypalStrategy implements PaymentStrategy {
private String emailId;
private String password;
public PaypalStrategy(String email, String pwd){
this.emailId=email;
this.password=pwd;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using Paypal.");
}
}
实现一个购物车并提供带有PaymentStrategy参数的payment方法。
Item.java
package com.example.strategy;
public class Item {
private String upcCode;
private int price;
public Item(String upc, int cost){
this.upcCode=upc;
this.price=cost;
}
public String getUpcCode() {
return upcCode;
}
public int getPrice() {
return price;
}
}
ShoppingCart.java
package com.example.strategy;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class ShoppingCart {
//List of items
List<Item> items;
public ShoppingCart(){
this.items=new ArrayList<Item>();
}
public void addItem(Item item){
this.items.add(item);
}
public void removeItem(Item item){
this.items.remove(item);
}
public int calculateTotal(){
int sum = 0;
for(Item item : items){
sum += item.getPrice();
}
return sum;
}
public void pay(PaymentStrategy paymentMethod){
int amount = calculateTotal();
paymentMethod.pay(amount);
}
}
可以注意到,ShoppingCart的payment方法需要提供一个PaymentStrategy参数且不会将该参数存储到对象的某个变量中。现在让我们新建一个测试类来测试下刚刚实现的策略模式。
ShoppingCartTest.java
package com.example.strategy;
public class ShoppingCartTest {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
Item item1 = new Item("1234",10);
Item item2 = new Item("5678",40);
cart.addItem(item1);
cart.addItem(item2);
//pay by weixin
cart.pay(new WeixinPayStrategy("myemail@example.com", "mypwd"));
//pay by credit card
cart.pay(new CreditCardStrategy("Pankaj Kumar", "1234567890123456", "786", "12/15"));
}
}
运行结果:
50 paid using Paypal.
50 paid with credit/debit card
策略设计模式类图
策略模式关键点
- 我们可以使用组合来为策略创建实例变量,但我们应该避免这种情况,因为我们希望将特定策略应用于特定任务;
- 策略模式与状态模式非常相似。区别之一是 Context 包含状态作为实例变量,并且可以有多个任务,其实现可以依赖于状态,而在策略模式中,策略作为参数传递给方法,并且上下文对象没有任何变量来存储它。
- 当我们对特定任务有多种算法并且我们希望我们的应用程序能够灵活地在运行时为特定任务选择任何算法时,策略模式非常有用。