<?php Class Fight{ public function __construct($options){ //... } } Class Force{ public function __construct($options){ //... } } Class Shot{ public function __construct($options){ //... } } //超能力工厂类 Class SuperModuleFactory{ public function makeModule($moduleName, $options){ switch($moduleName){ case 'Fight': return new Fight($options[0], $options[1]); case 'Force': return new Force($options[0]); case 'Shot': return new Shot($options[0], $options[1], $options[2]); // case 'more': ....... // case 'and more': ....... // case 'and more': ....... // case 'oh no! its too many!': ....... } } } Class Superman{ protected $power; public function __construct(array $modules) { //初始化工厂 $factory = new SuperModuleFactory; //通过工厂提供的方法制造需要的模块 // $this->power = $factory->makeModule('Fight',[9,100]); // $this->power = $factory->makeModule('Force',[50]); // $this->power = $factory->makeModule('Shot',[99,150,20]); /* $this->power = array( $factory->makeModule('Force',[45]), $factory->makeModule('Shot',[99,40,10]) ); */ //通过工厂提供的方法制造需要的模块 foreach($modules as $moduleName => $moduleOptions){ $this->power[] = $factory->makeModule($moduleName, $moduleOptions); } } } //创建超人 $superman = new Superman([ 'Fight' => [9, 100], 'Shot' => [99, 50, 2] ]); //“超人”的创建不再依赖任何一个“超能力”的类,如果修改了或者增加了新的超能力只需要针对修改SuperModuleFactory即可。 ?>
<?php //当超能力急需拓展的时候,如果依赖超能力工厂就会在switch里堆很多东西,我们需要制定统一接口作为一种“契约”,这样无论是谁创建出的模组,都符合这样的接口,就可以被正常使用。 interface SuperModuleInterface{ /** * 超能力激活方法 * * 任何一个超能力都得有该方法,并拥有一个参数 *@param array $target 针对目标,可以是一个或多个,自己或他人 */ public function activate(array $target); } /** * X-超能量 */ class XPower implements SuperModuleInterface{ public function activate(array $target){ // 这只是个例子。。具体自行脑补 } } /** * 终极炸弹 (就这么俗) */ class UltraBomb implements SuperModuleInterface{ public function activate(array $target){ // 这只是个例子。。具体自行脑补 } } //提供的模组实例必须是一个SuperModuleInterface接口的实现 //正是由于超人的创造变得容易,一个超人也就不需要太多的超能力,我们可以创造多个超人,并分别注入需要的超能力模组即可。 //开头到现在提到的一系列依赖,只要不是由内部生产(比如初始化、构造函数 __construct 中通过工厂方法、自行手动 new 的),而是由外部以参数或其他形式注入的,都属于依赖注入(DI) class Superman{ protected $module; public function __construct(SuperModuleInterface $module) { $this->module = $module; } } //下面就是一个典型的依赖注入 //超能力模组 $superModule = new XPower; //初始化一个超人,并注入一个超能力模组依赖 $superMan = new Superman($superModule); //我们需要自动化 —— 最多一条指令,千军万马来相见 //工厂模式升华 -- IoC容器 class Container{ protected $binds; protected $instance; public function bind($abstract, $concrete){ if($concrete instanceof Closure){ //instanceof Closure判断$concrete是否是一个闭包 $this->binds[$abstract] = $concrete; }else{ // instance 方法绑定一个已存在的对象实例到容器,这里不是绑定只是把concrete放到数组里 $this->instances[$abstract] = $concrete; } } public function make($abstract, $parameters = []){ if(isset($this->instances[$abstract])){ //已经是实例的 直接返回 //实例是已经被初始化过的 所以不需要再传入参数实例化 return $this->instances[$abstract]; } array_unshift($parameters, $this); return call_user_func_array($this->binds[$abstract], $parameters); } } //创建一个容器(后面称作超级工厂) $container = new Container; //向该超级工厂添加超能力模组的生产脚本 $container->bind('xpower', function($container) { return new XPower; }); //同上 $container->bind('ultrabomb', function($container){ return new UltraBomb; }); //向该超级工厂添加超人的生产脚本 $container->bind('superman', function($container, $moduleName){ return new Superman($container->make($moduleName)); }); //绑定后的XPower以及UltraBomb等超能力 使用$container->make()就可以返回实例 //$container->make('superman','xpower')可以实例化superman注入xpower的实例 //因为superman bind的时候闭包实现了对第二个参数(moduleName)的实例化 //所以就可以直接通过超级工厂类穿件superman的实例 //*********************** 华丽丽的分割线 ************************* //开始启动生产 $superman_1 = $container->make('superman','xpower'); $superman_1 = $container->make('superman','ultrabomb'); $superman_1 = $container->make('superman','xpower'); // ...随意添加 //要添加特异功能的参数我觉得应该修改代码如下,当然也需要修改一下前面的XPower类 $container->bind('xpower',function($container, $parameters){ return new XPower($parameters); //然后XPower的构造函数接收参数做相应处理 }); $container->bind('superman', function($container, $moduleName, $parameters){ return new Superman($container->make($moduleName, $parameters)); }); $superman_x = $container->make('superman','xpower',array(9,50,25)); //代码没有运行过不知道这样可不可行 只是一个思路 //实际上,真正的 IoC 容器更为高级。 //我们现在的例子中,还是需要手动提供超人所需要的模组参数,但真正的 IoC 容器会根据类的依赖需求,自动在注册、绑定的一堆实例中搜寻符合的依赖需求,并自动注入到构造函数参数中去。 //Laravel 框架的服务容器正是这么做的。实现这种功能其实理论上并不麻烦,但我并不会在本文中写出,因为……我懒得写。 ?>
http://laravelacademy.org/post/769.html