網頁

2018/2/26

Java 設計模式 策略模式 Strategy Pattern

策略模式(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廣告,感恩。



參考:

沒有留言:

張貼留言