laravel中的工厂模式(用于解耦代码)
我的上一篇博客提到过. 有关于ioc(inversion of control)控制反转的概念:
laravel 核心其实就是一个ioc容器,根据文章称为服务容器.
我打算用一个简单的故事来叙述ioc容器.
超人的能力. 依赖的诞生.
面向对象编程离不开一下几样东西:
接口,类,还有对象.
这其中,接口是类的原型,一个类必须要遵守你实现的接口;对象则是一个类实例化后的产物,我们通常把它称为一个实例.
当然这样说肯定不利于理解,我们就实际的写点伪代码.
怪物横行的世界,总归需要点超级人物来摆平.
我们把超人抽象化为一个类
class Superman
{
}
我们可以想想,一个超人诞生的时候肯定拥有至少一个超能力,这个超能力也可以抽象化为一个对象,为这个对象定义一个描述他的类吧.一个超能力肯定有多种属性,操作(方法),这个尽情的想象,但是我们目前先大致定义一个只有属性的超能力,至于能干啥我们以后再丰富.
class Power
{
//能力值
protected $ability;
//能力范围或者距离
protected $range;
public function __construct($ability,$range)
{
$this->ability =$ability;
$this->range =$ability;
}
}
这时我们再回去修改一下之前创建的超人类 让一个超人被创建的时候拥有一个超能力!这听起来是不是很smart
class Superman
{
protected $power;
public function __construct()
{
$this->power =new Power(999,100);
}
}
这样的话,当我们创建一个超人实例的时候,同时也创建了一个超能力实例,但是,我们看到了一点,超人和超能力之间不可避免的产生了一个依赖.
所谓依赖就是: 我若依赖你,我就不能离开你,否则,我就会报错......
在一个贯彻面向对象编程的项目中,这样的依赖随处可见. 少量的依赖并不会有太过直观的影响,我们随着这个例子逐渐铺开,就会感受到一股噩梦一般的体验.
可怕的依赖
依赖就和女友一样. 当你需要拥有逛街挑选衣服的能力时候,如果没有了依赖 你连挑选衣服的函数都无法调用.
在以上的例子中,超能力类实例化后是一个具体的超能力,但是我们知道,超人的超能力是多元化发展的,每种超能力的方法.属性都有不小的差异,没法通过一种类描述完全,我们现在进行修改,我们假设超人可以有一下多种超能力:
1,飞行:属性有:飞行速度,持续飞行时间.
2,蛮力: 属性有:力量值.
3,能量弹: 属性有:伤害值,射击距离,同时射击个数.
有了以上的概念,我们可以写下如下三个类:
class Flight
{
protected $speed;
protected $holdtime;
public function __construct($speed,$holdtime){}
}
class Force
{
protected $force;
protected $holdtime;
public function __construct($force){}
}
class Shot
{
protected $atk;
protected $range;
protected $limit;
public function __construct($atk,$range,$limit){}
}
为了省点力气 ,我没有写下构造函数里的全部内容.
这下超人就很忙了, 在超人初始化的时候,我们会根据需要来实例化起拥有的超能力. 大致如下:
class Superman
{
protected $power;
public function __construct()
{
$this->power =new Fight(9,100);
//$this->power =new Force(45);
//$this->power =new Shot(99,50,2);
$this->power=array(
new Force(45),
new Shot(99,50,2)
);
}
}
我们需要自己手动的在构造函数内 实例化一系列需要的类,这样并不好,可以想象,假如需求变更(pm怪物横行地球),需要更多的有针对性的创新超能力,或者需要变更超能力的方法,我们就必须重新改造超人.换句话说就是,改变超能力的同时,我还得重新制造个超人,效率太低了.新超人还没创造完成世界就早已经被毁灭.
这时,灵机一动的人想到:为什么不可以这样呢?超人的能力可以随时被更换,只需要添加或者更新一个芯片什么的或者其他装置啥的.这样就不需要重新来过了.
对,就是这样的.
我们不应该手动在超人类中固化了他的超能力初始化的行为.而转由外部负责,由外部创造超能力模组,装置芯片等等,植入超人体内的某一个接口,这个接口是一个既定的,只要这个模组满足这个接口的装置那就都可以被超人所利用. 可以提升,增加超人的某一种能力.
这种转由外部负责其依赖需求的行为,我们称之为控制反转(IOC);
实现控制反转,通常方式是使用工厂模式:
工厂模式:顾名思义,就是一个类所依赖的外部事物的实例,都可以被一个或多个工厂创建的这样的一种开发模式.
我们给超人制造超能力模组,我们创建了一个工厂,它可以制造各种各样的模组,且仅仅需要通过一个方法.
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]);
}
}
}
在这个时候,超人创建之初就可以使用这个工厂 成为超级赛亚人!:
class Superman
{
protected $power;
public function __construct()
{
//初始化工厂
$factory =new SuperModuleFactory;
//通过工厂提供的方法制造需要的模块
$this->power=$factory->makeModule('Fight',[9,100]);
//$this->power =$factory->makeModule('Force',[45]);
//$this->power =$factory->makeModule('Shot',[99,50,2]);
$this->power= array(
$factory->makeModule('Force',[45]),
$factory->makeModule('Shot',[99,50,2])
);
}
}
可以看的出,我们不在需要在超人初始化之初,去初始化许多第三方类,只需初始化,一个工厂类就可以满足初始化类的所有需求这就是控制反转最简单的一个模式. 但是这样感觉好像并没有起什么作用我们改一下这个制造类 就明白了
class Superman
{
protected $power;
public function __construct(array $modules)
{
//初始化写法
$factory =new SuperModuleFactory();
//通过工厂提供的方法制造需要的模块
foreach($modules as $moduleName=>$modulesOptions){
$this->power[]=$factory->makeModule($moduleName,$moduleOptions);
}
}
}
//创建超人
superman =new Superman([
'Fight'=>[9,100],
'Shot'=>[99,50,2]
]);
现在修改的结果令人满意,现在超人不需要依赖任何一个超能力类,我们如若修改了或者增加了新的超能力,只需要针对SuperModuleFactory既可,扩充超能力的同时不再需要重新编辑超人的类文件,使我们变的很轻松.这就是初步的ioc的设计模式的一个实现.
这个人暂时没有 freestyle