首先定义:用最简单的术语,您可以将策略模式定义为告诉对象执行某项工作并使用ANOTHER对象来完成该工作。
为了进一步阐明这一点,我将通过给它一个pay()*方法来稍微重新设计ShoppingCart:
public class ShoppingCart {
private final List<Item> items;
public ShoppingCart() {
items = new ArrayList<Item>();
}
public void addItem(Item item) {
items.add(item);
}
public double calcTotalCost() {
double total = 0.0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
public boolean pay(PaymentMethod method) {
double totalCost = calcTotalCost();
return method.pay(totalCost);
}
}
关于pay()方法要注意的是,它采用了类型PaymentMethod的一个参数–在我上面的定义中,PaymentMethod是“另一个”对象。
下一步是将PaymentMethod定义为接口。 为什么要使用界面? 这是因为该技术的强大之处在于您可以在运行时决定将哪种具体类型传递给ShoppingCart进行付款。 例如,给定“付款”界面:
public interface PaymentMethod {
public boolean pay(double amount);
}
然后,您可以定义任何具体的付款对象,例如Visa或MasterCard,例如:
public class Visa implements PaymentMethod {
private final String name;
private final String cardNumber;
private final Date expires;
public Visa(String name, String cardNumber, Date expires) {
super();
this.name = name;
this.cardNumber = cardNumber;
this.expires = expires;
}
@Override
public boolean pay(double amount) {
// Open Comms to Visa
// Verify connection
// Paybill using these details
return true; // if payment goes through
}
}
…和
public class MasterCard implements PaymentMethod {
private final String name;
private final String cardNumber;
private final Date expires;
public MasterCard(String name, String cardNumber, Date expires) {
super();
this.name = name;
this.cardNumber = cardNumber;
this.expires = expires;
}
@Override
public boolean pay(double amount) {
// Open Comms to Mastercard
// Verify connection
// Paybill using these details
return true; // if payment goes through
}
}
最后要做的就是通过单元测试来证明这一点:payBillUsingVisa
@Test
public void payBillUsingVisa() {
ShoppingCart instance = new ShoppingCart();
Item a = new Item("gloves", 23.43);
instance.addItem(a);
Item b = new Item("hat", 10.99);
instance.addItem(b);
Date expiryDate = getCardExpireyDate();
PaymentMethod visa = new Visa("CaptainDebug", "1234234534564567", expiryDate);
boolean result = instance.pay(visa);
assertTrue(result);
}
private Date getCardExpireyDate() {
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(2015, Calendar.JANUARY, 21);
return cal.getTime();
}
在上面的代码中,您可以看到我正在创建一个ShoppingCart,然后添加了一些商品。 最后,我以Visa对象的形式创建了一个新的PaymentMethod,并将其注入到pay(PaymentMethod method)函数中,这是问题的症结所在。 在另一种情况下,我可以轻松创建一个MasterCard对象并将其用作Visa的直接替代品-即作为参数传递的对象是在运行时确定的。
这就定义了战略模式,但这还不是博客的结尾。 如果您曾经使用过Spring,但从未听说过Strategy模式,那么所有这些都应该有点熟悉。 这是因为事实证明,Spring的家伙使用策略模式来支撑他们的整个技术。 如果以上面的示例为例,并进行一些细微更改,我可以得出:
@Component
public class SpringShoppingCart {
private final List<Item> items;
@Autowired
@Qualifier("Visa")
private PaymentMethod method;
public SpringShoppingCart() {
items = new ArrayList<Item>();
}
public void addItem(Item item) {
items.add(item);
}
public double calcTotalCost() {
double total = 0.0;
for (Item item : items) {
total += item.getPrice();
}
return total;
}
public boolean pay() {
double totalCost = calcTotalCost();
return method.pay(totalCost);
}
}
此化身与第一个化身之间的唯一区别是,使用@Autowired注释加载策略类Visa时,Spring会注入该策略类。 综上所述,我猜想这意味着策略模式是世界上最受欢迎的模式。
*出于讨论的目的,我假设ShoppingCart可以自己付费,但是这是否正确,是一个全新的博客……
参考: Captain Debug的Blog博客中的JCG合作伙伴 Roger Hughes的《策略模式》 。
翻译自: https://www.javacodegeeks.com/2012/04/strategy-pattern.html