????????Laravel的源码中有许多地方都用到了建造者模式,像我们要做数据库查询的时候(就像下面这串代码)直接调用方法传入参数就直接可以代替数据库查询语句。
//等价于select * from login where num=$num and pwd=$pwd
$sql?=?DB::table('login')
????????????->where('num','=',$num)
????????????->where('pwd','=',$pwd)
????????????->get();
????????还有很多类似于这种用法的其实其源代码都使用建造者模式。比如下面我们详细分析一个,绑定上下文机制中的源码也用到了这种模式。Laravel的container中提供了绑定上下文机制,解析一个对象的时候,有些对象是需要外部的一些依赖的。那他在创建的时候就要用到上下文把依赖引入。上下文绑定的意思就是专门处理实例化时候有依赖关系情况的一种绑定。比如有时侯我们可能有两个类使用同一个接口,但我们希望在每个类中注入不同实现就可以用到绑定上下文。container定义了简单、平滑的接口。
$this->app->when(PhotoController::class)
->needs(Filesystem::class)
->give(function () {
return Storage::disk('local');
});
? ? ? ?源码中,在container中有一个when方法,这个方法直接生成一个上下文绑定 ContextualBindingBuilder 对象,传入 container 对象和 $concrete。进入到这个 ContextualBindingBuilder 类可以看到该类提供了两个方法,needs 和 give方法。 needs 方法把 $abstruct 存储起来,返回当前对象,以致可以继续链式操作。而give 方法则又重新调用了 $container 中的 addContextualBinding(), 这个就是添加上下文绑定的方法,把这些参数存入 contextual 数组。
????????当一个类实例化需要一些外部依赖的时候,就要用到上下文绑定。把外部依赖通过 need 传递给他。还可以通过 give 存储 when 对应的实现。存入到容器中那个负责上下文的那个数组中,这个数组将会在取出某个对象的时候,他对应绑定的依赖也会被取出。
????????如果不用这种模式写的语法就会非常的繁琐。通过绑定上下文构造器,我们可以把精力聚焦到组装外部依赖中去,而不再需要全局考量 依赖的每个地方。 就如这里我们看到的,在我们链式调用上下文绑定构造器的不同方法时,其实我们就在对不同的绑定的内容进行定义。 比如我们在调用 table 方法时,我们关注的就是 SQL 的表选择部分。有两个类使用同一个接口,就可以实现在每个类中注入不同实现,减少繁琐的语法、依赖等处理的时间。
文件路径:
抽象建造者:Illuminate\Container\ContextualBindingBuilder.php
具体建造者:Illuminate\Contracts\Container\ContextualBindingBuilder.php
产品类:我们一般习惯于直接指定绑定各个内容,也就让协调者Director的作用变得非常低。 所以在查询构造器的使用部分,我们就见不到它的身影了。
class ContextualBindingBuilder implements ContextualBindingBuilderContract
{
public function needs($abstract)
{
$this->needs = $abstract;
return $this;
}
public function give($implementation)
{
foreach (Util::arrayWrap($this->concrete) as $concrete) {
$this->container->addContextualBinding($concrete, $this->needs, $implementation);
}
}
}
类图
时序图
?
|