小菜分享-设计模式(装饰者模式)--欢迎批评指点! [ 技术分享 ]
小菜技术分享第二篇。
场景:经理A的咖啡店今天开业了,经理A找到小菜,让他帮忙设计一个销售程序(私下交易,经理A照顾小菜,给小菜个私活) 仔细分析,咖啡店肯定会卖多种咖啡,不同咖啡不同口味,不同顾客选用不同搭配,比如有的顾客要加糖,有的不加,有的加奶,有的不加。
这样的话怎么搞呢? 先用我们低级的思维--过程开发写一下试试
class Coffee{
//销售咖啡
public function saleCoffee(){
$coffeeType = '接收用户指令需要什么咖啡';
$suggar = '接收用户加糖'?'接收用户加糖':'';
$milk = '接收用户加奶'?'接收用户加奶':'';
$coffee = '';
$_suggar = $_milk = null;
switch($coffeeType){
case '黑咖啡':
$coffee = $this->createCoffee_Black();
break;
case '摩卡':
$coffee = $this->createCoffee_Mocha();
break;
case '拿铁':
$coffee = $this->createCoffee_Latte();
break;
case '美式':
$coffee = $this->createCoffee_Americano();
break;
}
//是否需要加糖
if($suggar){
$_suggar = $this->addSuggar($coffee);
}
//是否需要加奶
if($milk){
$_milk = $this->addSuggar($coffee);
}
//将咖啡,糖返回给用户
return array][$coffee,$_suggar,$_milk];//如果没有奶,没有糖,返回空;
}
//制作一杯黑咖啡
private function createCoffee_Black(){
//工序不同,配料不同,杯子不同
return $coffee;//制作完成,返回一杯咖啡
}
//制作一杯摩卡
private function createCoffee_Mocha(){
/工序不同,配料不同,杯子不同
return $coffee;//制作完成,返回一杯咖啡
}
//制作一杯拿铁
private function createCoffee_Latte(){
//工序不同,配料不同,杯子不同
return $coffee;//制作完成,返回一杯咖啡
}
//制作一杯美式
private function createCoffee_Americano(){
/工序不同,配料不同,杯子不同
return $coffee;//制作完成,返回一杯咖啡
}
//加糖
private function addSuggar(){
//收糖钱1元(一般情况是不要钱的,为了例子需要,这里加糖要钱)
return 糖;
}
//加奶
private function addMilk(){
//收奶钱1元(一般情况是不要钱的,为了例子需要,这里加糖要钱)
return 奶;
}
}
程序手打,没有测试,会有错误。 仔细看就知道了,如果以后经理A咖啡店增加了其他品种的咖啡或其他品种的配料 要修改的地方会很多。 而且或多了很多if else 的判断。这种if else 分支判断多了,整个程序就会越来越乱。
对于开发,if else 判断不是说用的越多越不好。而是,对于这种组合模式的程序,使用if else判断完全是行不通的,以为你不确定组合的基数是多少,后续扩展。 而真正使用if else 的是,两条路选择时,对于与后续无扩展变化。例如if(是会员){有人会说了,后续会员会有多个等级也是不确定的,这个具体等级就是细分了,但是,不管什么等级,他们都是会员所以可以用if else 后续再处理多个等级的会员,V1,V2,V3...这是不建议用if else}else{} . PS(这里啰嗦了一下) 完全是个人想法,有不同想法的欢迎留言批评。
继续 改用面向对象的来开发
做面向对象,第一步就是分析,先不急着写代码。分析就是抽象思维来思考。什么是抽象思维呢就是看待事物从不同角度出发: 例如, 平常人看两个人在散步,可以抽象为人类,两个人类在散步(他的眼里是两个人在走路) 生物学家看两个人在散步,可以抽象为动物,两个人在散步(他的眼里是两个动物在走路)(往高粒度分析人也是动物) 细胞学家看两个人在散步,可以抽象为细胞,两个人在散步(他的眼里是两堆细胞在移动) (往更高的粒度分析了)
回到正题, 咖啡店,咖啡怎么分析
1咖啡属于咖啡? 2咖啡属于饮品? 3咖啡属于液体?
你觉得上面三个抽象,哪个合适? 我觉得是2。虽然1也是可以的,但是对于后续扩展不广,如果以后经理A的咖啡店卖奶茶了呢?抽象类如果是1咖啡的话,奶茶不属于咖啡啊! 但是如果抽象为饮品,以后咖啡店升级卖奶茶了也可以继承饮品类,以后买果汁了也没问题。。。 如果选3抽象为液体,这个维度有点高了,就目前的需求是用不到(如果是安检系统或许会用到)
abstract class Drink{
public $name;//饮品名字
//饮品
abstract public function sale();
}
abstract class Coffee extends Drink{
public function beizi(){
//所有咖啡统一用陶瓷杯子
}
abstract public function sale();
}
//黑咖啡
class Coffee_Black extends Coffee{
public function __construct(){
$this->name = '黑咖啡';
}
public function sale(){
//咖啡销售价格
return 35;
}
}
//摩卡
class Coffee_Mocha extends Coffee{
public function __construct(){
$this->name = '摩卡';
}
public function sale(){
return 30;
}
}
//拿铁
class Coffee_Latte extends Coffee{
public function __construct(){
$this->name = '拿铁';
}
public function sale(){
return 25;
}
}
//美式
class Coffee_Americano extends Coffee{
public function __construct(){
$this->name = '美式';
}
public function sale(){
return 28;
}
}
//装饰器
class Decorator extends Drink{
private $_drink;
public function __construct(Drink $drink){
$this->_drink = $drink;
}
}
//加糖
class Suggar extends Decorator{
public function sale(){
//加糖,在原金额基础上+1元
return $this->_drink->sale()+1;
}
}
//加奶
class Milk extends Decorator{
public function sale(){
//加奶,在原金额基础上+1元
return $this->_drink->sale()+1;
}
}
//后续扩展,如果加酒就单独写一个类,加什么都单独一个类,与其他代码不发生冲突。
开放封闭原则
收银台调用:
要一杯美式咖啡,加糖,加奶
public function client(){
//美式咖啡
$Americano = new Coffee_Americano();
$suggar = new Suggar($Americano);
$milk = new Milk($suggar );
echo $milk->name;
echo $milk->sale();
}
累了,不写了,大概就这意思。 代码没验证。有错正常。 为自己记录:2017年5月18日 今天爱车被电瓶车装了,妈的,太气人了。没赔钱就走了
共 2 条回复
灰太狼
最后登录:2023-07-14
在线时长:76小时17分
- 粉丝28
- 金钱3290
- 威望150
- 积分5550