1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | <?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即可。 ?> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | <?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