[笔试题] 用 PHP 写一个微波炉

在网上看到一个笔试题,感觉挺有意思的,然后我尝试着解一解,欢迎各位大佬指正。

代码题(用OOP的思想编码,注意代码规范) 写出你的思路,最好有代码

用php写一个微波炉,注意物品正加热时不能开门,带皮带壳食物不能被加热。

感谢@MrJing@minororange两位大佬的建议,更进一步理解了OOP,现更新第二版。

第二版

<?php
/**
 * Created by PhpStorm.
 * User: arun
 * Date: 2019-04-30
 * Time: 16:10
 */

/**
 * 厨房用具
 * Interface kitchenWare
 */
interface kitchenWare {

    /**
     * 加工食材
     * @param Food $food
     * @return mixed
     */
    public function process(Food $food);

    /**
     * 是否正在加工
     * @return mixed
     */
    public function hasProcess();
}

/**
 * 微波炉
 * Class MicrowaveOven
 */
class MicrowaveOven implements kitchenWare
{
    /**
     * 是否加热中
     * @var bool
     */
    protected $is_heat = false;

    /**
     * @param Food $food
     * @return mixed|string
     */
    public function process(Food $food)
    {
        if ($this->hasProcess()) {
            return '已有食物在加热,无法打开';
        } else {
            if ($food->hasShuck() || $food->hasPericarp()) {
                return '食物带壳或者带皮,无法进行加热';
            } else {
                $this->is_heat = true;
                return '食物加热中,加热完成即可取出';
            }
        }
    }

    /**
     * 是否正在加工
     * @return bool|mixed
     */
    public function hasProcess()
    {
        return $this->is_heat;
    }
}

/**
 * 烤箱
 * Class Oven
 */
class Oven implements kitchenWare
{
    /**
     * 是否烧烤中
     * @var bool
     */
    protected $is_heat = false;

    /**
     * @param Food $food
     * @return mixed|string
     */
    public function process(Food $food)
    {
        if ($this->is_heat) {
            return '已有食物在烤制,无法打开';
        } else {
            if ($food->hasShuck()) {
                return '食物带壳,无法进行烤制';
            } else {
                $this->is_heat = true;
                return '食物烤制中,完成即可取出';
            }
        }
    }

    /**
     * 是否正在加工
     * @return bool|mixed
     */
    public function hasProcess()
    {
        return $this->is_heat;
    }
}

/**
 * 食物
 * Class Food
 */
class Food
{
    /**
     * 是否带壳
     * @var bool
     */
    protected $is_shuck = false;
    /**
     * 是否带皮
     * @var bool
     */
    protected $is_pericarp = false;

    /**
     * Food constructor.
     * @param bool $is_shuck
     * @param bool $is_pericarp
     */
    public function __construct(bool $is_shuck, bool $is_pericarp)
    {
        $this->is_shuck = $is_shuck;
        $this->is_pericarp = $is_pericarp;
    }

    /**
     * 判断是否带壳
     * @return bool
     */
    public function hasShuck()
    {
        return $this->is_shuck;
    }

    /**
     * 判断是否带皮
     * @return bool
     */
    public function hasPericarp()
    {
        return $this->is_pericarp;
    }
}

/**
 * 烹饪
 * Class Cooking
 */
class Cooking
{
    /**
     * @var kitchenWare
     */
    protected $kitchenWare;

    /**
     * Cook constructor.
     * @param kitchenWare $kitchenWare
     */
    public function __construct(kitchenWare $kitchenWare)
    {
        $this->kitchenWare = $kitchenWare;
    }

    /**
     * 烹饪食物
     * @param Food $food
     * @return mixed
     */
    public function cooking(Food $food)
    {
        $data = $this->kitchenWare->process($food);
        return $data;
    }
}

/**
 * 微波炉加热
 * @return mixed
 */
function test()
{
    $cooking = new Cooking(new MicrowaveOven());
    $food = new Food(false, false);
    $result = $cooking->cooking($food);
    $result2 = $cooking->cooking($food);
    var_dump($result, $result2);
}

/**
 * 烤箱烤制
 * @return mixed
 */
function test2()
{
    $cooking = new Cooking(new Oven());
    $food = new Food(false, true);
    $result =  $cooking->cooking($food);
    $result2 =  $cooking->cooking($food);
    var_dump($result, $result2);
}

test();
test2();

第一版

<?php
/**
 * Created by PhpStorm.
 * User: arun
 * Date: 2019-04-30
 * Time: 16:10
 */

/**
 * 厨房用具
 * Interface kitchenWare
 */
interface kitchenWare {
    /**
     * 加工食材
     *
     * @param $food
     * @return mixed
     */
    public function process($food);
}

/**
 * 微波炉
 * Class MicrowaveOven
 */
class MicrowaveOven implements kitchenWare
{
    /**
     * 是否加热中
     * @var bool
     */
    protected $is_heat = false;

    public function process($food)
    {
        if ($this->is_heat) {
            return '已有食物在加热,无法打开';
        } else {
            if ($food['is_shuck'] || $food['is_pericarp']) {
                return '食物带壳或者带皮,无法进行加热';
            } else {
                $this ->is_heat = true;
                return '食物加热中,加热完成即可取出';
            }
        }
    }
}

/**
 * 烤箱
 * Class Oven
 */
class Oven implements kitchenWare
{
    /**
     * 是否烧烤中
     * @var bool
     */
    protected $is_heat = false;

    public function process($food)
    {
        if ($this->is_heat) {
            return '已有食物在烤制,无法打开';
        } else {
            if ($food['is_shuck']) {
                return '食物带壳,无法进行烤制';
            } else {
                $this ->is_heat = true;
                return '食物烤制中,完成即可取出';
            }
        }
    }
}

/**
 * 食物
 * Class Food
 */
class Food
{
    /**
     * 是否带壳
     * @var bool
     */
    protected $is_shuck = false;
    /**
     * 是否带皮
     * @var bool
     */
    protected $is_pericarp = false;

    /**
     * Food constructor.
     * @param bool $is_shuck
     * @param bool $is_pericarp
     */
    public function __construct(bool $is_shuck, bool $is_pericarp)
    {
        $this->is_shuck = $is_shuck;
        $this->is_pericarp = $is_pericarp;
    }

    public function getFood()
    {
        return [
            'is_shuck' => $this->is_shuck,
            'is_pericarp' => $this->is_pericarp,
        ];
    }
}

/**
 * 烹饪
 * Class Cooking
 */
class Cooking
{
    /**
     * @var kitchenWare
     */
    protected $kitchenWare;

    /**
     * Cook constructor.
     * @param kitchenWare $kitchenWare
     */
    public function __construct(kitchenWare $kitchenWare)
    {
        $this->kitchenWare = $kitchenWare;
    }

    /**
     * 烹饪食物
     * @param $food
     * @return mixed
     */
    public function cooking($food)
    {
        $data = $this->kitchenWare->process($food);
        return $data;
    }
}

/**
 * 微波炉加热
 * @return mixed
 */
function test()
{
    $cooking = new Cooking(new MicrowaveOven());
    $food = new Food(false, false);
    $result = $cooking->cooking($food->getFood());
    $result2 = $cooking->cooking($food->getFood());
    var_dump($result, $result2);
}

/**
 * 烤箱烤制
 * @return mixed
 */
function test2()
{
    $cooking = new Cooking(new Oven());
    $food = new Food(false, true);
    $result =  $cooking->cooking($food->getFood());
    $result2 =  $cooking->cooking($food->getFood());
    var_dump($result, $result2);
}

test();
test2();
本作品采用《CC 协议》,转载必须注明作者和本文链接
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 文章来源blog.arunfung.com
本帖由系统于 4年前 自动加精
arunfung
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 26

interface 中的 processCooking 对象的 cooking 中限制 $food 变量的类型:

public function process(Food $food);

参照 @MrJing 的建议,在 Food 对象中定义两个方法


public function hasShuck(){
    return $this->is_shuck;
}

public function hasPericarp(){
    return $this->is_pericarp;
}

最后调用:

$result = new Cooking(new MicrowaveOven())->cooking(new Food(false,false));

传递对象比传递数组要好一点,因为传递数组,在使用的时候有可能数组里面没有这个元素,容易出现 bug 。
传递对象的话,if ($food['is_shuck']) 改成 $food->hasShuck() ,一是更加语义化,二是避免上述 bug。

4年前 评论
大张 4年前
wonbin

赞一个,一看到这个题目我直接暴躁了,以为是热饭那个微博炉呢

4年前 评论
arunfung

@wonbin :grinning: 哈哈,是热饭的那个微波炉啊,有那么一点标题党,只是我个人对 oop 的一点理解,希望可以帮助更多人

4年前 评论

:joy: :joy: :joy:,还真是微波炉呢。

4年前 评论

Food 声明为一个接口,有2个方法:hasShuck、hasPericarp。这样就感觉更“OOP”一点了

4年前 评论

interface 中的 processCooking 对象的 cooking 中限制 $food 变量的类型:

public function process(Food $food);

参照 @MrJing 的建议,在 Food 对象中定义两个方法


public function hasShuck(){
    return $this->is_shuck;
}

public function hasPericarp(){
    return $this->is_pericarp;
}

最后调用:

$result = new Cooking(new MicrowaveOven())->cooking(new Food(false,false));

传递对象比传递数组要好一点,因为传递数组,在使用的时候有可能数组里面没有这个元素,容易出现 bug 。
传递对象的话,if ($food['is_shuck']) 改成 $food->hasShuck() ,一是更加语义化,二是避免上述 bug。

4年前 评论
大张 4年前

非常有意思的题目

4年前 评论

你好,有点想不明白,为什么test 方法中用调用两次$cooking->cooking($food)

4年前 评论
arunfung

@Leo_Phoenix 你好,这主要想表达的是正在加热,无法开门的情况。

4年前 评论
锋子

改了下。挺有意思的 :joy:

file
file
file
file

4年前 评论

你看这微波炉它又大又圆

4年前 评论

else用的有些多呀,有些可以去掉

4年前 评论
arunfung

@xun1009 :smiley:如果有想法,可以简单给出建议,我后续更新进文章中,thanks

4年前 评论
arunfung

@锋子 :+1:改进很好的扩展了食物类,但是没有根据题意做出改进,稍稍有点偏题额,哈哈, :smiley:不过还是鼓励多方面思考,尝试更优解的实现。

4年前 评论

可以再帮我写个电饭锅么

4年前 评论
guanhui07

刚吃完午饭..

4年前 评论

下划线命名差评

4年前 评论
锋子

@arunfung 哈哈偷了个懒。觉得有意思就简单试了下,嘿嘿。

4年前 评论

这绝对是个超级人工智能的微波炉,要是当年我用微波炉加热鸡蛋的时候是这个款微波炉。。。呃,也不用那么的糗了 :flushed:

4年前 评论

哈哈 一开始差点暴躁了

4年前 评论

你好,PHP进程挂了,我要热饭

4年前 评论

提供一种思路, 用状态机实现 可以动态更改状态,这个是代码关键 代码如下 (只写了大概 可以跑 但还是可以优化的)

4年前 评论

下班抽空搞的 写的有点子粗糙 仅提供一种思路吧
状态目前只有 Open, Heat, Close 有需要可以扩展其他状态,这套维护性和拓展性都还好,不过会冗余一些东西,关键在于它的状态可以动态调整,按需使用,仅供参考。

//微波炉状态接口 (因为在每个状态下,用户都有可能做以下动作,具体每个状态自己实现)
interface IMicrowaveState
{
    //开启微波炉
    public function open();
    //打开添加食物
    public function add();
    //加热
    public function heat();
    //关闭微波炉
    public function close();
}
//微波炉状态基类
abstract class ABMicrowaveStateState implements IMicrowaveState
{

    //更多的状态自己加
    const STATUS_OPENED = 1;
    const STATUS_HEATED = 2;
    const STATUS_CLOSED = 3;

    /**
     * 状态机
     */
    protected $_machine = null;

    /**
     * 食物类
     * @var Food object
     */
    protected $_food = null;

    /**
     * 状态 已打开;已加热;已关闭  默认关闭
     * @var
     */

    protected $_status;

    public function __construct(MicrowaveStateMachine $machine)
    {
        $this->_machine = $machine;
        $this->_food = $machine->getFood();
    }

    /**
     * 要求子类必须实现 (下同) 标明状态 便于获取 打日志等
     * @return mixed
     */
    abstract function getStatus();

    /**
     * @return mixed
     */
    abstract function getStatusText();

}
//打开状态
class OpenMicrowaveState extends ABMicrowaveState
{
    public function getStatus()
    {
        return self::STATUS_OPENED;
    }
    public function getStatusText()
    {
        return '已开启';
    }
    public function open()
    {
        echo 'Microwave 已经打开, 无需重复打开' .PHP_EOL;

    }
    public function add()
    {
        if ($this->_food->isPacked()) {
            echo '带皮带壳食物不能被加热' .PHP_EOL;
            exit();
        } else {
            echo '添加' . $this->_food->getName() . '成功' .PHP_EOL;
        }

    }
    public function heat()
    {
        echo $this->_food->getName(). '正在加热,请稍等' .PHP_EOL;
        $this->_machine->setState($this->_machine->getHeatState());

    }
    public function close()
    {
        echo 'V bo lu 已关闭' .PHP_EOL;
        $this->_machine->setState($this->_machine->getCloseState());

    }
}
//加热状态
class HeatMicrowaveState extends ABMicrowaveState
{

    public function getStatus()
    {
        return self::STATUS_HEATED;
    }

    public function getStatusText()
    {
        return '加热中';
    }

    public function open()
    {
        echo 'Microwave 正在加热, 无需重复打开' .PHP_EOL;

    }

    public function add()
    {
        echo 'Microwave 正在加热, 不可以添加东西' .PHP_EOL;
        exit();
    }

    public function heat()
    {
        echo 'Microwave 正在加热, 无需重复加热' .PHP_EOL;
        exit();
    }

    public function close()
    {
        echo 'Microwave 关闭完成' .PHP_EOL;
        $this->_machine->setState($this->_machine->getCloseState());

    }
}
//关闭状态
class CloseMicrowaveState extends ABMicrowaveState
{
    public function getStatus()
    {
        return self::STATUS_CLOSED;
    }

    public function getStatusText()
    {
        return '已关闭';
    }

    public function open()
    {
        echo 'Microwave 打开完成' .PHP_EOL;
        $this->_machine->setState($this->_machine->getOpenState());

    }

    public function add()
    {
        echo '请先打开V bo lu ' .PHP_EOL;
        exit();

    }

    public function heat()
    {
        echo '请先打开V bo lu ' .PHP_EOL;
        exit();

    }

    public function close()
    {
        echo 'Microwave 已完毕,无需再次关闭' .PHP_EOL;

    }
}
//状态管理机器类  可以理解为发动机
class MicrowaveStateMachine implements IMicrowaveState
{
    protected $_food;
    /**
     * 当前状态对象
     * @var ABMicrowaveState
     */
    protected $_currentState;
    protected $_openState;
    protected $_heatState;
    protected $_closeState;

    public function __construct(Food $food)
    {
        $this->_food = $food;
        $this->_openState = new OpenMicrowaveState($this);
        $this->_heatState = new HeatMicrowaveState($this);
        $this->_closeState = new CloseMicrowaveState($this);
        $this->_currentState = new CloseMicrowaveState($this);
    }

    public function setState(IMicrowaveState $state)
    {
        $this->_currentState = $state;
    }

    public function open()
    {
        $this->_currentState->open();
        return $this;
    }

    public function add()
    {
        $this->_currentState->add();
        return $this;
    }

    public function heat()
    {
        $this->_currentState->heat();
        return $this;
    }

    public function close()
    {
        $this->_currentState->close();
        return $this;
    }

    public function getFood()
    {
        return $this->_food;
    }

    public function getOpenState()
    {
        return $this->_openState;
    }

    public function getHeatState()
    {
        return $this->_heatState;
    }

    public function getCloseState()
    {
        return $this->_CloseState;
    }

}
//食物类  这里可以采用接口  
class Food
{
    /**
     * 食物名称
     * @var string $name
     */
    protected $name;
    protected $type;

    /**
     * 食物是否有包装(是否带皮带壳)
     * @var bool $isPacked
     */
    protected $isPacked;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function setType($type)
    {
        $this->type = $type;
        return $this;
    }

    public function setIsPacked($isPacked)
    {
        $this->isPacked = $isPacked;
        return $this;
    }
    public function getName()
    {
        return $this->name;
    }

    public function isPacked()
    {
        return $this->isPacked;
    }

}
//TestUse       

        $food = new Food('大米');
        $food->setIsPacked(false);
        //默认微波炉关闭
        $machineTestOne = new MicrowaveStateMachine($food);
//        $machineTestOne->open()->add()->heat()->close();
Microwave 打开完成
添加大米成功
大米正在加热,请稍等
Microwave 关闭完成

        //测试物品正加热时不能开门   状态是动态调整的
        $machineTestOne->open()->add()->heat()->add();

Microwave 打开完成
添加大米成功
大米正在加热,请稍等
Microwave 正在加热, 不可以添加东西
 //换带壳子的
        $foodTwo = new Food('核桃');

        $foodTwo->setIsPacked(true);
        $machineTestTwo = new MicrowaveStateMachine($foodTwo);
        $machineTestTwo->open()->add()->heat()->close();

Microwave 打开完成
带皮带壳食物不能被加热
4年前 评论
arunfung (楼主) 4年前
chery (作者) 4年前
wangchunbo 4年前

装饰者模式?最近在看 Head First 设计模式,感觉和装饰者模式有些类似

4年前 评论

才知道微波炉不能加热带壳带皮的东西 :stuck_out_tongue_closed_eyes:

4年前 评论
arunfung

@aoxiang594 :smile:哈哈,赶紧东西热起来

4年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!