写在前面的话:
最近利用下班的空余时间看了一下Laravel框架中的源码。发现他所用到的设计方法和理念都是已经存在的。之前使用JavaWeb的时候也常用到。所以最近我想通过对框架中源码的分析,进一步提高我对设计模式的理解。
在Laravel中,服务容器是整个系统功能调度的核心,在JavaWeb中类似于ApplicationContext 。它提供了一系列在框架运行的过程中需要的一系列服务。服务容器就是提供服务的载体,而服务是系统运行过程中需要的东西,如系统配置,文件路径等。线面先来介绍一下一些设计模式作为铺垫。
依赖与耦合
服务容器可以提供很多内容,而在这些功能中,解决依赖实现解耦是应用服务器的关键。其实服务容器就是一个IoC容器。IoC其实就是控制反转模式,主要用来解决系统组件间的相互依赖,这也是面向对象设计语言最避讳的点之一。
下面都过一个示例来说明什么是依赖,怎么解决系统对象之间的耦合:
<?php
//设计公共接口
interface Play
{
public function go();
}
//实现不同的玩耍方案
class Panic implements Play
{
public function go()
{
echo "去野炊";
}
}
class Song implements Play
{
public function go()
{
echo "去KTV唱歌";
}
}
class Hiking implements Play
{
public function go()
{
echo "去徒步旅行";
}
}
//设计公司类,该类实现休息的功能时依赖玩耍的实例
class Company
{
protected $relaxMethod;
public function __construct()
{
//Attention!!! 这里产生了依赖
$this->relaxMethod = new Panic();
}
public function relax()
{
$this->relaxMethod->go();
}
}
这里要实现的功能是公司周末的休息方案,而出去玩可能有很多方案,比如KTV唱歌,野炊,徒步旅行。代码“$this->relaxMethod = new Panic();”中实例化了野炊,于是两个代码之间的耦合就产生了。这会导致一个严重的问题,如果需求经常改变,就需要修改实例化的对象。所以我们不应该在“公司类”的内部写死了“休息方案”的初始化行为,而是把控制权交给外部负责,载系统运行期间,将这种依赖关系通过动态注入的方式实现。
工厂模式
休息方案的实例化过程是经常需要改变的,所以我们把这部分的职责交给外部来管理。面向对象有个设计准则叫OCP,意思是发现变化封装变化大家可看我的这篇 博客。一种简单的实现方案是利用简单工厂模式实现。示例如下:
class RelaxMethodFactory{
public function createRelaxMethod($name)
{
switch ($name) {
case 'Panic':
return new Panic();
break;
case 'Song':
return new Song();
break;
case 'Hiking':
return new Hiking();
break;
default:
exit('老铁,出毛病了');
break;
}
}
}
class Company
{
protected $relaxMethod;
public function __construct($relaxMethodName)
{
//通过工厂产生依赖的休息方案实例
$factory = new RelaxMethodFactory();
$this->$relaxMethod = $factory->createRelaxMethod($relaxMethodName);
}
public function relax()
{
$this->relaxMethod->go();
}
}
这里我们添加了“休息方案”工厂,在“公司团体”实例化的过程中指定休息的方案。但是从本质上并不能解决系统耦合的关系。表面上看似“公司团体”与“休息方案”之间的耦合没有了。但是却变成了“公司团体”与“休息方案工厂”之间的耦合。当需求增加时,我们需要修改简单工厂模式,如果依赖过多,工厂类过于庞大,不容易维护。
IoC模式
控制反转是将组件间的依赖关系从程序内部提到外部容器来管理,而依赖注入是将依赖通过外部以参数的形式注入,比如我们写Controller时,有时候需要访问Request对象,可以在方法中声明。
解决系统间依赖根本是,没有用new关键字来实例化对象,不需要人为关注类之间的依赖关系,只要在容器填充过程中实现类与依赖接口之间的关系。这里类的实例化实际上与Spring容器类似。在容器中直接填充实例化对象。Laravel的服务容器指得就是这个容器,它的核心功能是IoC容器用以解决依赖注入,面对服务容器中的填充部分称为服务提供者。
持续关注。。。