第6课:IOC控制反转

我们都有一个理想,想我们的项目中的功能模块都完全独立,没有耦合,但是又能很好的交互
IOC就是致力于解决这样的问题

IOC说白了就是用一个中间件,一般是个类,来作为其他功能类的通信桥梁,各个功能类各自独立

说了这个中心思想,是不是觉得和设计模式中的工厂模式有点类似?
可以说IOC就是用工厂模式的思想来实现的,比工厂模式复杂的是他要在工厂类里面负责各个功能类方法调用,有点累

举例说明:
我们有个蔬菜接口,接口里有个方法,显示颜色
一个番茄类,一个黄瓜类,实现了蔬菜接口
<?php
interface Vegetables {
    public function showColor();
}

class Tomato implements Vegetables {
	private $color;

    function getColor() {
        return $this->color;
    }

    function setColor($value) {
        $this->color = $value;
    }
    
    function showColor(){
        echo "Tomato Color:" . $this->color;
    }
}

class Cucumber implements Vegetables {
    private  $color;

    function getColor(){
        return $this->color;
    }

    function setColor($value){
        $this->color = $value;
    }

    function showColor(){
        echo "Cucumber Color:" . $this->color;
    }
}

?>

工厂类(这里是关键):
<?php
class ClassFactory {
    private $arr_conf;

    function ClassFactory($config_file){
        //读取配置文件内容
	$content = include 'config.json';

        //去除注释
        $content = preg_replace("<\/\/.*?\s>", "", $content);

        //转成数组
        $this->arr_conf=json_decode($content,true);
    }

     function getBean($class_id){
        //查找匹配 $class_id 的类
        while(true){
            //挨个测试
            $conf = each($this->arr_conf);

            //找不到,返回 null
            if($conf==false) return null;

            if(strcmp($class_id, $conf["value"]["id"])===0){

                //如果匹配则装入类文件
                include_once($conf["value"]["class_file"]);

                //生成类的实例
                $obj = new $conf["value"]["class_name"]();

                //查找被设置的属性(这里也是比单纯的工厂类复杂的地方,要运行一些配置好的方法)
                $arr_prop = $conf["value"]["properties"];
                while($prop = each($arr_prop)){
                    //生成属性的设置方法 setXXX ,第一个字母大写
                    $set_method="set". ucwords($prop["value"]["name"]);

                    //调用设置方法,并设置预设值
                    $obj->$set_method($prop["value"]["value"]);
                }

                //找到第一个,返回实例
                return $obj;
            }
        }
    }
}

?>

配置文件
//备注使用双反斜杆
[
    {
        //类ID,方便工厂查找
        "id": "Tomato",

        //类名
        "class_name":"Apple",

        //类文件
        "class_file":"Vegetables.php",

        //属性设置
        "properties":[
            {
                "name":"color",
                "value":"Red"
            }
        ]
    },

    {
        "id": "Cucumber",
        "class_name":"Cucumber",
        "class_file":"Vegetables.php",
        "properties":[
            {
                "name":"color",
                "value":"Green"
            }
        ]
    }
]

调用
<?php
include_once("ClassFactory.php");
$factory = new ClassFactory("config.json");

$fruit = $factory->getBean("Tomato");
echo $fruit->showColor() .'<br />';

$fruit = $factory->getBean("Cucumber");
echo $fruit->showColor() .'<br />';

显示:
Tomato Color:Red
Cucumber Color:Green

从上面的调用过程可以看到,getBean可以作为一个统一的方法,里面根据不同的值,可以实现调用对应的类的不同的方法,完成各自的功能
这个调用的过程无需牵扯Tomato或者Cucumber,只需要和工厂类打交道,工厂类通过配置文件,决定getBean被调用时会发生什么