策略模式(Strategy Pattern)屬於設計模式中的行為模式(behavioral design pattern)。策略模式也稱作Policy Pattern。
當一件任務有許多種不同算法,並讓客戶端在程式執行時決定要使用哪一種算法時,可使用策略模式。
策略模式最好的例子就是Collections.sort()
,根據傳入不同的Comparator
實作讓物件有不同的排序方式。
範例一
參考於Strategy Design Pattern in Java – Example Tutorial
這個例子用購物車以不同的付款方式結帳來說明策略模式。
例如在購物網站買東西付款時,通常提供多種付款方式,例如用信用卡(Credit card),Paypal等來付款,雖然都是付款(一件任務),但每種付款方式的實作細節不同(一件任務中有不同算法),這時候就可以使用策略模式。
因為都是付款,所以把"付款"這個行為抽出來獨立成一個模組。
定義一個付款策略介面PaymentStrategy
,裡面有個付款方法pay()
。由於有各種付款方式,所以pay()
的具體實作由繼承PaymentStrategy的類別來定義。
PaymentStrategy
package com.abc.demo.payment;
public interface PaymentStrategy {
public void pay(int amount);
}
第一種付款方式是使用信用卡付款,所以定義一個信用卡付款類別,繼承PaymentStrategy
介面。並在CreditCardStrategy.pay()
中實作信用卡付款的細節。
CreditCardStrategy
package com.abc.demo.payment;
public class CreditCardStrategy implements PaymentStrategy {
private String name; // 持卡人名稱
private String cardNumber; // 信用卡號碼
private String cvv; // 驗證代碼
private String dateOfExpiry; // 信用卡到期日
public CreditCardStrategy(String name, String cardNumber, String cvv, String dateOfExpiry){
this.name = name;
this.cardNumber = cardNumber;
this.cvv = cvv;
this.dateOfExpiry = dateOfExpiry;
}
@Override
public void pay(int amount) {
System.out.println("金額" + amount + "元已使用信用卡付款");
}
}
第二種付款方式是使用PayPal付款,所以定義一個Paypal
付款類別,繼承PaymentStrategy
介面。
PaypalStrategy
package com.abc.dmeo.payment;
public class PaypalStrategy implements PaymentStrategy {
private String email;
private String password;
public PaypalStrategy (String email, String password){
this.email = email;
this.password = password;
}
@Override
public void pay(int amount) {
System.out.println("金額" + amount + "元已使用Paypal付款");
}
}
同樣地PaypalStratefy.pay()
實作以Paypal付款的細節。
以上已經完成付款的策略模式,接下來實作購物車和商品項目,來模擬購買過程來觀察策略模式的運作。
Item
代表商品類別,包括了商品碼及商品價格資訊,可以新增並放入購物車。
Item
package com.abc.demo.item;
public class Item {
private String upcCode; // 商品碼
private int price; // 商品價格
public Item(String upcCode, int price){
this.upcCode = upcCode;
this.price = price;
}
public String getUpcCode(){
return this.upcCode;
}
public int getPrice(){
return this.price;
}
}
購物車ShoppingCart
,可以加入或移除商品,並提供付款方法,但付款方法的細節是依照傳入的付款方式類別來決定。
ShoppingCart
package com.abc.demo.cart;
import java.util.ArrayList;
import java.util.List;
import com.abc.demo.item.Item;
import com.abc.demo.payment.PaymentStrategy;
public class ShoppingCart {
List<Item> itemList;
public ShoppingCart(){
this.itemList = new ArrayList<Item>();
}
public void addItem(Item item){
itemList.add(item);
}
public void removeItem(Item item){
itemList.remove(item);
}
public int calculateTotal(){
int sum = 0;
for(Item item : itemList){
sum += item.getPrice();
}
return sum;
}
public void pay(PaymentStrategy paymentStrategy){
int amount = calculateTotal();
paymentStrategy.pay(amount);
}
}
最後使用一個main來測試,建立一些商品並加入購物車,然後使用不同方式結帳。
ShoppingCartTest
package com.abc.demo.test;
import com.abc.demo.cart.ShoppingCart;
import com.abc.demo.item.Item;
import com.abc.demo.payment.CreditCardStrategy;
import com.abc.demo.payment.PaypalStrategy;
public class ShoppingCartTest {
public static void main(String[] args){
ShoppingCart shoppingCart = new ShoppingCart();
Item item1 = new Item("Noodle", 100);
Item item2 = new Item("hotdog", 30);
shoppingCart.addItem(item1);
shoppingCart.addItem(item2);
// 用信用卡付款
shoppingCart.pay(new CreditCardStrategy("jack","6503070019199487","123","20161222"));
// 用paypal付款
shoppingCart.pay(new PaypalStrategy("jack@abc.com","1234567890"));
}
}
執行結果如下
金額130元已使用信用卡付款
金額130元已使用Paypal付款
從以上範例可以觀察到,當使用不同方式付款,只要提供該方式的類別即可,不用再去修改購物車該如何付款,因為該如何付款決定在付款方式的實作類別。
策略模式和狀態模式(State Pattern)很類似,差別在於狀態模式的狀態會被儲存,並在執行時根據儲存的狀態來改變方法的實作細節,而策略模式是以參數將實作傳入要執行的方法。
如果覺得文章有幫助的話還幫忙點個Google廣告,感恩。
參考:
沒有留言:
張貼留言