Leveraging code reuse in a world without mixins First, we need our interface. All the other objects conform to this interface, so they are all polymorphic.
|
interface IDiscountCart { public get_total(); public get_shipping(); } |
The DiscountCart is the most primitive of the Discount types. It gives the customer a 15% discount on their entire cart. Inheritance.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
class DiscountCart implements IDiscountCart { public $discount_percent = 15; public function __construct($cart = null) { if ($cart) { $this->items = $cart->items; } } public function get_total() { $total = 0; foreach ($this->items as $item) { $total += $item->quantity * $item->amount; } return $total * ($discount_percent / 100); } public function get_shipping() { $shipping_total = 0; foreach ($this->items as $item) { $shipping_total += $item->quantity * $item->shipping_amount; } return $shipping_total; } } |
The VolumeDiscount inherits from the DiscountCart, and overrides with its own discount based on the volume of each product in the cart. Inheritance with a method override.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
class VolumeDiscountCart extends DiscountCart { $parent_cart = null; $disounct_minimum = 10; $discount_percent = 10; public function __construct($cart = null) { parent::__construct($cart); $this->parent_cart = $cart; } public function get_total() { $total = 0; foreach ($this->item as $item) { if ($item->quantity >= $this->discount_minimum) { $total += ($item->amount - $item->amount * ($this->discount_percent / 100)); } } reutrn $total; } // get_shipping inherited } |
There is another discount which adds free shipping. Inheritance with a property override.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
class FreeShippingDiscountCart extends DiscountCart { // No discount here. public $discount_percent = 0; public function __construct($cart = null) { parent::__construct($cart); } // get_total inherited public function get_shipping() { return 0; } } |
Now, there is a very special customer type: the Frequent Customer. We give them a Volume discount AND they get free shipping all the time. If we had mixins, we could just “mix in” the free shipping, but since this is php (or C# for that matter) I do it this way:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
class FrequentCustomerDiscountCart implements IDiscountCart { private $_volume_discount_cart = null; private $_free_shipping_cart = null; public function __construct($cart = null) { $this->_simple_discount_cart = new VolumeDiscountCart($cart); $this->_free_shipping_cart = new FreeShippingDiscountCart($cart); } public function get_total() { return $this->_volume_discount_cart->get_total(); } public function get_shipping() { return $this->_free_shipping_cart->get_shipping(); } } |
This lets the FreeShippingDiscountCart be compatible with any IDiscountCart polymorphism and leverage inherited traits from its private objects. That way, if Free Shipping gets complicated (ex: drop-shipped or sale items are not eligible) I don’t have to re-implement the exceptions.