前言
写一个商场收银相关接口,要求输入当前商品单价和数量,最后展示商品总价及所有商品信息
收银系统1.0
<?php
//收银系统
class store
{
//总价
public $total = 0;
public $goodsList = [];
//录入价钱
public function click($goodsName, $price, $num)
{
$currentPrice = round($price * $num, 2);
$this->total = round($this->total + $currentPrice, 2);
$this->goodsList[] = [
'goods_name' => $goodsName,
'price' => $price,
'num' => $num,
'all_price' => $currentPrice,
];
}
//结算金额
public function show()
{
echo "总价:$this->total<br/>";
foreach ($this->goodsList as $item) {
echo "{$item['goods_name']} {$item['price']}X{$item['num']}={$item['all_price']}<br/>";
}
}
}
$store = new store();
$store->click('苹果', 2, 5.5);
$store->click('香蕉', 5, 2);
$store->click('荔枝', 1, 11);
$store->click('橙子', 2, 1.6);
$store->click('车厘子', 2, 60);
$store->click('榴莲', 2, 42);
$store->show();
输出内容:
总价:239.2
苹果 2X5.5=11
香蕉 5X2=10
荔枝 1X11=11
橙子 2X1.6=3.2
车厘子 2X60=120
榴莲 2X42=84
大鸟指导
- 现在要求商场搞活动,所有商品打八折,你要怎么改动? 如果是打五折,打七折呢?
收银系统1.1
<?php
//收银系统
class store
{
//总价
public $total = 0;
public $goodsList = [];
//录入价钱
public function click($goodsName, $price, $num, $discount = 1)
{
switch ($discount) {
case 1:
$currentPrice = round($price * $num, 2);
break;
case 0.7:
$currentPrice = round($price * $num * 0.7, 2);
break;
case 0.8:
$currentPrice = round($price * $num * 0.8, 2);
break;
case 0.5:
$currentPrice = round($price * $num * 0.5, 2);
break;
}
$this->total = round($this->total + $currentPrice, 2);
$this->goodsList[] = [
'goods_name' => $goodsName,
'price' => $price,
'num' => $num,
'discount' => $discount,
'all_price' => $currentPrice,
];
}
//结算金额
public function show()
{
echo "总价:$this->total<br/>";
foreach ($this->goodsList as $item) {
if ($item['discount'] == 1) {
echo "{$item['goods_name']} {$item['price']}X{$item['num']}={$item['all_price']}<br/>";
} else {
echo "{$item['goods_name']} {$item['price']}X{$item['num']}X{$item['discount']}={$item['all_price']}<br/>";
}
}
}
}
$store = new store();
$store->click('苹果', 2, 5.5, 0.5);
$store->click('香蕉', 5, 2, 0.5);
$store->click('荔枝', 1, 11, 0.5);
$store->click('橙子', 2, 1.6, 0.5);
$store->click('车厘子', 2, 60, 0.5);
$store->click('榴莲', 2, 42, 0.5);
$store->show();
输出如下
总价:119.6
苹果 2X5.5X0.5=5.5
香蕉 5X2X0.5=5
荔枝 1X11X0.5=5.5
橙子 2X1.6X0.5=1.6
车厘子 2X60X0.5=60
榴莲 2X42X0.5=42
大鸟指导
- 现在灵活性好多了,但是重复代码很多
- 如果商城出促销活动,满300抵100,你怎么改动这份代码呢
- 想想满300抵100,满700抵200,八折,七折,五折这些信息,有哪些相同的,哪些不同的
面向对象的编程,并不是类越多越好,类的划分只是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类
使用工厂模式实现
<?php
//现金收费抽象类
abstract class cashSuper
{
public abstract function acceptCash($money);
}
//正常收费子类
class cashNormal extends cashSuper
{
//正常收费,原价返回
public function acceptCash($money)
{
return round($money, 2);
}
}
//打折收费子类
class cashRebate extends cashSuper
{
private $moneyRebate;
//打折费率,初始化时,必须输入打折费率,如八折就是0.8
public function __construct($moneyRebate)
{
$this->moneyRebate = round($moneyRebate, 1);
}
//乘以打折费率返回
public function acceptCash($money)
{
return round($money * $this->moneyRebate, 2);
}
}
//返利收费子类
class cashReturn extends cashSuper
{
private $moneyCondition; //返现条件
private $moneyReturn; //返现金额
//返利收费,初始化时必须输入返利条件和返利值,比如满300返100,则moneyCondition为300,moneyReturn为100
public function __construct($moneyCondition, $moneyReturn)
{
$this->moneyCondition = round($moneyCondition);
$this->moneyReturn = round($moneyReturn);
}
//如果大于返利条件,则减去返利值
public function acceptCash($money)
{
if ($money >= $this->moneyCondition) {
return round($money - $this->moneyReturn, 2);
} else {
return round($money, 2);
}
}
}
//现金收费工厂类
class CashFactory
{
public function createCashAccept($type)
{
$obj = null;
switch ($type) {
case '正常收费':
$obj = new cashNormal();
break;
case '满300返100':
$obj = new cashReturn(300, 100);
break;
case '打8折':
$obj = new cashRebate(0.8);
break;
}
return $obj;
}
}
//结合之前的场景
class store
{
//总价
public $total = 0;
public $goodsList = [];
//录入价钱
public function click($goodsName, $price, $num, $type)
{
$totalMoney = round($num * $price, 2);
$currentPrice = (new CashFactory())->createCashAccept($type)->acceptCash($totalMoney);
$this->total = round($this->total + $currentPrice, 2);
$this->goodsList[] = [
'goods_name' => $goodsName,
'price' => $price,
'num' => $num,
'type' => $type,
'all_price' => $currentPrice,
];
}
//结算金额
public function show()
{
echo "总价:$this->total<br/>";
foreach ($this->goodsList as $item) {
echo "{$item['goods_name']} {$item['price']}X{$item['num']}[{$item['type']}]=>{$item['all_price']}<br/>";
}
}
}
$store = new store();
$store->click('苹果', 2, 5.5, '打8折');
$store->click('香蕉', 5, 2, '正常收费');
$store->click('荔枝', 1, 11, '打8折');
$store->click('橙子', 2, 1.6, '正常收费');
$store->click('车厘子', 6, 60, '满300返100');
$store->click('榴莲', 2, 42, '打8折');
$store->show();
输出如下
总价:358
苹果 2X5.5[打8折]=>8.8
香蕉 5X2[正常收费]=>10
荔枝 1X11[打8折]=>8.8
橙子 2X1.6[正常收费]=>3.2
车厘子 6X60[满300返100]=>260
榴莲 2X42[打8折]=>67.2
大鸟指导
- 如果要改动优惠力度,就要花心思维护工厂类
- 虽然工厂类能解决这个问题,但这未必是最好的方法
策略模式样例
<?php
//抽象算法类
abstract class strategy{
//算术方法
public function algorithmInterface(){}
}
class conCreateStrategy extends strategy{
//算术A实现方法
public function algorithmInterface()
{
echo '算术A实现';
}
}
class conCreateStrategyB extends strategy{
//算术B实现方法
public function algorithmInterface()
{
echo '算术B实现';
}
}
class conCreateStrategyC extends strategy{
//算术C实现方法
public function algorithmInterface()
{
echo '算术C实现';
}
}
class context{
private $strategy;
public function __construct($strategy)
{
$this->strategy = $strategy;
}
//上下文接口
public function contextInterface(){
$this->strategy->algorithmInterface();
}
}
//实际调用
(new context(new conCreateStrategy()))->contextInterface();
(new context(new conCreateStrategyB()))->contextInterface();
(new context(new conCreateStrategyC()))->contextInterface();
输出内容:
算术A实现算术B实现算术C实现
大鸟指导
- 由于实例化不同的策略,最终在调用contextInterface()得到结果就会不一样
策略模式实现收银系统
策略模式实现收银系统
<?php
//现金收费抽象类
abstract class cashSuper
{
public abstract function acceptCash($money);
}
//正常收费子类
class cashNormal extends cashSuper
{
//正常收费,原价返回
public function acceptCash($money)
{
return round($money, 2);
}
}
//打折收费子类
class cashRebate extends cashSuper
{
private $moneyRebate;
//打折费率,初始化时,必须输入打折费率,如八折就是0.8
public function __construct($moneyRebate)
{
$this->moneyRebate = round($moneyRebate, 1);
}
//乘以打折费率返回
public function acceptCash($money)
{
return round($money * $this->moneyRebate, 2);
}
}
//返利收费子类
class cashReturn extends cashSuper
{
private $moneyCondition; //返现条件
private $moneyReturn; //返现金额
//返利收费,初始化时必须输入返利条件和返利值,比如满300返100,则moneyCondition为300,moneyReturn为100
public function __construct($moneyCondition, $moneyReturn)
{
$this->moneyCondition = round($moneyCondition);
$this->moneyReturn = round($moneyReturn);
}
//如果大于返利条件,则减去返利值
public function acceptCash($money)
{
if ($money >= $this->moneyCondition) {
return round($money - $this->moneyReturn, 2);
} else {
return round($money, 2);
}
}
}
class cashContext
{
private $cashObj;
public function __construct($obj)
{
$this->cashObj = $obj;
}
public function getResult($money)
{
return $this->cashObj->acceptCash($money);
}
}
//结合之前的场景
class store
{
//总价
public $total = 0;
public $goodsList = [];
//录入价钱
public function click($goodsName, $price, $num, $type)
{
$totalMoney = round($num * $price, 2);
$obj = null;
switch ($type) {
case '正常收费':
$obj = new cashContext(new cashNormal());
break;
case '满300返100':
$obj = new cashContext(new cashReturn(300, 100));
break;
case '打8折':
$obj = new cashContext(new cashRebate(0.8));
break;
}
$currentPrice = $obj->getResult($totalMoney);
$this->total = round($this->total + $currentPrice, 2);
$this->goodsList[] = [
'goods_name' => $goodsName,
'price' => $price,
'num' => $num,
'type' => $type,
'all_price' => $currentPrice,
];
}
//结算金额
public function show()
{
echo "总价:$this->total<br/>";
foreach ($this->goodsList as $item) {
echo "{$item['goods_name']} {$item['price']}X{$item['num']}[{$item['type']}]=>{$item['all_price']}<br/>";
}
}
}
$store = new store();
$store->click('苹果', 2, 5.5, '打8折');
$store->click('香蕉', 5, 2, '正常收费');
$store->click('荔枝', 1, 11, '打8折');
$store->click('橙子', 2, 1.6, '正常收费');
$store->click('车厘子', 6, 60, '满300返100');
$store->click('榴莲', 2, 42, '打8折');
$store->show();
输出如下
总价:358
苹果 2X5.5[打8折]=>8.8
香蕉 5X2[正常收费]=>10
荔枝 1X11[打8折]=>8.8
橙子 2X1.6[正常收费]=>3.2
车厘子 6X60[满300返100]=>260
榴莲 2X42[打8折]=>67.2
大鸟指导
- 策略模式是出来了,但是判断逻辑又回到了click()方法里
- 可以让策略模式的Context与简单工厂结合
策略模式与简单工厂结合
<?php
//现金收费抽象类
abstract class cashSuper
{
public abstract function acceptCash($money);
}
//正常收费子类
class cashNormal extends cashSuper
{
//正常收费,原价返回
public function acceptCash($money)
{
return round($money, 2);
}
}
//打折收费子类
class cashRebate extends cashSuper
{
private $moneyRebate;
//打折费率,初始化时,必须输入打折费率,如八折就是0.8
public function __construct($moneyRebate)
{
$this->moneyRebate = round($moneyRebate, 1);
}
//乘以打折费率返回
public function acceptCash($money)
{
return round($money * $this->moneyRebate, 2);
}
}
//返利收费子类
class cashReturn extends cashSuper
{
private $moneyCondition; //返现条件
private $moneyReturn; //返现金额
//返利收费,初始化时必须输入返利条件和返利值,比如满300返100,则moneyCondition为300,moneyReturn为100
public function __construct($moneyCondition, $moneyReturn)
{
$this->moneyCondition = round($moneyCondition);
$this->moneyReturn = round($moneyReturn);
}
//如果大于返利条件,则减去返利值
public function acceptCash($money)
{
if ($money >= $this->moneyCondition) {
return round($money - $this->moneyReturn, 2);
} else {
return round($money, 2);
}
}
}
class cashContext
{
private $cashObj;
//此处传入一个字符串,而不是对象
public function __construct($objType)
{
switch ($objType) {
case '正常收费':
$this->cashObj = new cashNormal();
break;
case '满300返100':
$this->cashObj = new cashReturn(300, 100);
break;
case '打8折':
$this->cashObj = new cashRebate(0.8);
break;
}
}
public function getResult($money)
{
return $this->cashObj->acceptCash($money);
}
}
//结合之前的场景
class store
{
//总价
public $total = 0;
public $goodsList = [];
//录入价钱
public function click($goodsName, $price, $num, $type)
{
$totalMoney = round($num * $price, 2);
$currentPrice = (new cashContext($type))->getResult($totalMoney);
$this->total = round($this->total + $currentPrice, 2);
$this->goodsList[] = [
'goods_name' => $goodsName,
'price' => $price,
'num' => $num,
'type' => $type,
'all_price' => $currentPrice,
];
}
//结算金额
public function show()
{
echo "总价:$this->total<br/>";
foreach ($this->goodsList as $item) {
echo "{$item['goods_name']} {$item['price']}X{$item['num']}[{$item['type']}]=>{$item['all_price']}<br/>";
}
}
}
$store = new store();
$store->click('苹果', 2, 5.5, '打8折');
$store->click('香蕉', 5, 2, '正常收费');
$store->click('荔枝', 1, 11, '打8折');
$store->click('橙子', 2, 1.6, '正常收费');
$store->click('车厘子', 6, 60, '满300返100');
$store->click('榴莲', 2, 42, '打8折');
$store->show();
输出如下
总价:358
苹果 2X5.5[打8折]=>8.8
香蕉 5X2[正常收费]=>10
荔枝 1X11[打8折]=>8.8
橙子 2X1.6[正常收费]=>3.2
车厘子 6X60[满300返100]=>260
榴莲 2X42[打8折]=>67.2
大鸟指导
- 对比简单工厂与策略模式+简单工厂:
- 简单工厂
(new CashFactory())->createCashAccept($type)->acceptCash($totalMoney);
- 策略模式+简单工厂
(new cashContext($type))->getResult($totalMoney)
- 简单工厂需要认识2个类,CashFactory和cashSuper
- 策略模式+简单工厂只需要认识一个cashContext,耦合度更低
- 简单工厂
- 策略模式是一种定义一系列算法的方式,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同.它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合
- 策略模式可以封装几乎所有类型的规则,只要在分析过程中听到需要在不同时间应用不同的业务规则,就可以考虑用策略模式处理这种变化的可能性
- 在基本的策略模式中,选择所用具体实现的职责由客户端对象来承担,并转给策略模式的Context对象,如果结合了简单工厂模式,则可以有Context承担选择判断,减轻客户端的压力