<?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