2011-09-13 60 views
2

我正在制定一個方法來計算以PHP編寫的購物車的總數,並且希望獲得有關用於處理不同條件的良好設計模式的一些反饋。我正試圖爲管理員提供多種計算折扣的策略。管理員可以選擇在應用稅款之前或之後應用折扣,以及將折扣應用於運輸或不運輸。這給出了我的任務的概述。基於多個變量狀態的條件語句的一個很好的設計模式

變量

我對這個任務有可能的值以下變量:

$tax_option: '前' '後'

$shipping_option,: '是',「否'

除了這兩個變量之外,計算總值的公式也會根據$subtotal(購物車中物品的數量)和$reduction(總折扣金額)。

一般來說,我的邏輯是我測試了$tax_option$shipping_option變量的4種組合中的每一種。我還需要更改$subtotal小於或等於$reduction的情況的公式。總之,我有8種不同的條件。

的可能性

我的身影,我真的在這裏有3種不同的選擇:if語句,一個switch陳述或戰略格局。我將展示if聲明的結構和策略模式,但將排除switch的可能性,因爲在這種情況下這看起來不正確。

if聲明

這裏是我正在考慮if語句的一般模式。請注意,我知道我可以稍微重組,但無論出於何種原因,這對我來說更具可讀性。

if($tax_option == 'after' && $shipping_option == 'yes') 
{ 
    if($subtotal <= $reduction) 
    { 

    } 
    else 
    { 

    } 
} 
elseif($tax_option == 'before' && $shipping_option == 'yes') 
{ 
    if($subtotal <= $reduction) 
    { 

    } 
    else 
    { 

    } 
} 
elseif($tax_option == 'before' && $shipping_option == 'no') 
{ 
    if($subtotal <= $reduction) 
    { 

    } 
    else 
    { 

    } 
} 
elseif($tax_option == 'after' && $shipping_option == 'no') 
{ 
    if($subtotal <= $reduction) 
    { 

    } 
    else 
    { 

    } 
} 
else 
    $new_total = $total; 

策略模式

網上四處尋找解決這個問題後,我瞭解了Strategy Pattern,這看起來真棒。我在這裏開始工作,並不介意對此進行一些反饋。到目前爲止,它看起來像下面的代碼,明顯地刪除了一些例程。

class DPPCalculateTotal 
{ 
    protected $formulas = array(); 

    public function DPPCalculateTotal($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 
     foreach($this->formulas as $formula) 
     { 
      if($formula->test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction)) 
      { 
       return $formula->calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction); 
      } 
     } 
    } 

    function add_formula(DPPFormula $formula) 
    { 
     $this->formulas = $formula; 
    } 
} 

interface DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction); 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction); 
} 

class AfterTaxesYesShippingGreaterSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class AfterTaxesYesShippingLesserSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class AfterTaxesNoShippingGreaterSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class AfterTaxesNoShippingLesserSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class BeforeTaxesYesShippingGreaterSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class BeforeTaxesYesShippingLesserSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class BeforeTaxesNoShippingGreaterSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

class BeforeTaxesNoShippingLesserSubotal implements DPPFormula 
{ 
    public function test($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 

    public function calculate_total($tax_option, $shipping_option, $total, $subtotal, $shipping, $tax, $coupons_amount, $reduction) 
    { 

    } 
} 

的問題

1)在你看來,這將是在這裏,最好的方法?

2)在這種情況下策略模式的優勢是什麼?

3)由於這是我第一次嘗試戰略模式,它看起來像我正朝着正確的方向前進嗎?

非常感謝您的意見!我很開心學習這種模式,並會欣賞我可以得到的任何反饋!

+0

如果單個公式不太複雜,那麼轉到if語句。特別是如果你發現它更可讀。如果您在if語句中放置$ shipping_option =='yes',則評估較少。 –

回答

3

我認爲您的方向是正確的。有了戰略模式,隨着應用程序變得更大或需求變更(根據我的經驗,這種情況是10次中的9次),隨後添加新戰略非常容易。

我建議多做一個叫Order的類,把你所有的訂單細節封裝在裏面,然後傳遞物件。你的測試和計算方法會有點整潔

interface DPPFormula 
{ 
    public function test(OrderInteface $order); 

    public function calculate_total(OrderInterface $order); 
} 

interface OrderInterface 
{ 
    function setTotal($total); 
    function getTotal(); 
} 

那麼你可以做類似的東西,以

$order->setTotal($calculator->DPPCalculateTotal()); 

根據您的複雜性,你可能會或可能不希望使用的接口,爲Order。我強烈建議你使用一個,因爲這進一步增加了抽象。

+0

感謝您的建議gilden!我很欣賞關於這一點的提示,這讓事情變得更容易。我並沒有這麼想,但是看看這兩種方法,我已經可以看到戰略模式在那裏有巨大的收益。由於我實際上正在構建現有系統,因此我不會構建訂單界面,因爲已經處理了這個邏輯(如此糟糕),但是感謝您提供了很好的建議。 – tollmanz

0

我認爲有可能將總價分成可貼現金額和不可貼現金額。然後,您將折扣應用於可折扣金額,並添加其餘部分,如下面的僞代碼:

extra = 0 
if (tax_option) 
    subtotal += tax(subtotal) 
else 
    extra += tax(subtotal) 
if (delivery_option) 
    subtotal += delivery 
else 
    extra += delivery 
if (subtotal > reduction) 
    subtotal -= reduction 
else 
    // stuff here 
subtotal += extra 
+0

謝謝尼爾!這裏的問題是公式根據所提到的變量的狀態而變化。例如,如果管理員想要在稅前和運費上應用折扣,該公式會變得有點瘋狂。此外,如果折扣等於小計,則必須考慮使總計爲0。但是,一個管理員可能想要收取運費,因爲折扣不適用於運費。看看這如何變得非常快速? – tollmanz

+1

@沙丁似乎你需要一堆方法add_tax,add_shipping,apply_discount,然後以適當的順序應用它們。也許可以用戰略模式來做到這一點。也許別人會解決如何做到這一點。 – Neil

+0

尼爾......我完全同意。問題是我正在接入一個非常混亂的系統。我的代碼旨在獲取已計算的值並根據這些值計算新的總計。我希望整個系統被重寫。 – tollmanz

-1

你有沒有想過使用查找表/數組?可以讓別人更清楚些。數組鍵可以是各種組合的字符串,那麼您可以將您想要的任何值與查找鍵相關聯。

$lookup = array(
    'taxo-after:shipo-yes'=> array('reduction'=>100), 
    'taxo-after:shipo-no'=> array('reduction'=>100), 
    'taxo-before:shipo-yes'=> array('reduction'=>100), 
    'taxo-before:shipo-no'=> array('reduction'=>100), 
    ... 
); 

$lookup_key = 'taxo-'.$tax_option.':'.'shipo-'.$shipping_option; 
if ($subtotal < $lookup[$lookup_key]['reduction']) { 
} else { 
} 

這幾乎取代了你的整個第一個代碼示例。 1個數組聲明和1個if語句。您可以添加一百個可能性,而不會有任何性能損失或更多的代碼。

+0

我沒有想到這種方法。不幸的是,它不允許我根據匹配的條件來應用公式。 – tollmanz

相關問題