我正在研究一种方法来计算用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 :(得分:4)
我认为你正朝着正确的方向前进。随着策略模式的推出,随着应用程序变大或需求发生变化(根据我的经验,情况就是9次中的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
的界面。我强烈建议你使用一个,因为这进一步增加了抽象。
答案 1 :(得分: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
答案 2 :(得分:-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语句。您可以添加一百种可能性而不会造成任何性能损失或更多代码。