沙滩星空的博客沙滩星空的博客

理解控制反转和依赖注入容器

将Boy对Girl的依赖转移到了类定义之外,这样Boy不在主动的依赖Girl,而是需要在初始化的时候将Girl作为一个参数传入构造函数。像这种依赖不是主动的初始化解决,而是由外部传入依赖解决的方式,我们就可以理解为依赖注入。这种将依赖的控制权转交出去的行为便是控制反转

通过接口(interface)实现依赖注入解耦:


interface Girl {
    public function cook();
}

class LolitaGirl implement Girl {
    public function cook() {
        echo "萝莉做的饭还需努力";
    }
}

class LadyGirl implement Girl {
    public function cook() {
        echo "女士做的饭很好吃";
    }
}

 class Boy {
    // 我需要个妹子做饭给我吃
    protected $girl;
    
    public function __construct(Girl $girl) {
        $this->girl = $girl;
    }
 }
 
 $lolitaGirl = new LolitaGirl();
 $ladyGirl = new LadyGirl();
 
 // 我要吃萝莉的饭
 $boy = new Boy($lolitaGirl);
 // 我要吃女士的饭
 $boy = new Boy($ladyGirl);

使用魔术方法__set(),__get()动态添加依赖


class Boy {
    protected $module;
    
    public __construct() {
        $this->module = [];
    }
    
    public function __set($name, $value) {
        $this->module[$name] = $value;
    }
    
    public function __get($name) {
        if (array_key_exists($name, $this->module)) {
            return $this->module[$name];
        }else {
            throw new \Exception($name . 'is not exists');
        }
    }
}

$boy = new Boy();
$boy->ladyGirl = new LadyGirl();
$boy->skill = new Skill(10000);

抽象工厂模式:
Boy所依赖的属性越来越多,会出现很多setter。你会发现这些setter的行为都一样,完全可以抽象出一个工厂帮你去set


class FactoryBoy {
    public function createModule($module, $option = []) {
        if (class_exists($module)) {
            if ([] == $option) {
                return new $module();
            } else {
                return new $module($option);
            }
        }else {
            throw new \Exception('class ' . $module . ' is not exists!');
        }
    }
}

class Boy {

    public function __construct($modules) {
        $factory = new FactoryBoy();
        
        foreach($modules as $moduleName => $moduleOption) {
            $this->data[] = $factory->createModule($moduleName, $moduleOption);
        }
    }
}

$boy = new Boy([
    LadyGirl::class => '',
    Skill::class => 10000,
]);


依赖注入容器(dependency injection container):


class Container {
    protected $binds = [];
    protected $instances = [];
    
    public function bind($abstract, $concrete) {
        if ($concrete instanceof Closure) {
            $this->binds[$abstract] = $concrete;
        } else {
            $this->instances[$abstract] = $concrete;
        }
    }
    
    public function make($abstract, $parameters = []) {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        array_unshift($parameters, $this);//往$parameters数组添加元素$this
 
        return call_user_func_array($this->binds[$abstract], $parameters);
    }
}

$container = new Container();
$container->bind('Boy', function($container, $moduleName) {
    return new Boy($container->make($moduleName));
});

$container->bind('LadyGirl', function($container) {
    return new LadyGirl();
})

// 一个拥有了ladyGirl做饭的Boy
$boy = $container->make('Boy', ['LadyGirl']);


call_user_func_array函数使用说明


function foobar($arg, $arg2) {
    echo __FUNCTION__, " got $arg and $arg2\n";
}
class foo {
    function bar($arg, $arg2) {
        echo __METHOD__, " got $arg and $arg2\n";
    }
}


// Call the foobar() function with 2 arguments
call_user_func_array("foobar", array("one", "two"));

// Call the $foo->bar() method with 2 arguments
$foo = new foo;
call_user_func_array(array($foo, "bar"), array("three", "four"));

依赖注入与容器 https://www.cnblogs.com/tingyugetc/p/6234560.html
call_user_func_array函数说明 https://www.php.net/manual/zh/function.call-user-func-array.php
Laravel 服务容器实例教程--深入理解控制反转(IoC)和依赖注入(DI)https://laravelacademy.org/post/769.html
未经允许不得转载:沙滩星空的博客 » 理解控制反转和依赖注入容器

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址