在使用laravel框架的时候,经常能看到facade,今天就来研究一下到底什么是facade。
一、定义
Facade(外观)模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用。它是为子系统中的一组接口所提供的一个一致的界面。
Facade并不是laravel框架独有的东西,它属于设计模式中的外观模式。
以上的定义有些绕,我们举个例子来说:
家中有很多电器,然而统一有一个总电源开关,总电源开关能够同时控制家中所有的电器,电源开关即为这个系统的外观模式设计。
二、为什么要使用facade
1.为了降低复杂性,常常将系统划分为若干个子系统。但是如何做到各个系统之间的通信和相互依赖关系达到最小呢?这时候就需要facade模式了。
为子系统中的一组接口提供一个一致的界面, Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。
2.精简代码
如果我们不使用facade模式,想把服务容器里的对象取出来,并调用他的方法,就需要obj->method(arg1,arg2)->func(arg3,arg4);这种代码是可以接受的,但是还不够优雅,例如定义一个路由,也要这样复杂的的形似,就很不友好。facade为我们使用 Laravel 的功能提供了简单、易记的语法,而无需记住必须手动注入或配置的长长的类名。
三、结构
facade的组成分为上图的三个部分:
外观角色facade:被客户client调用,知道各个子系统的功能。
子系统角色subsystem:实现子系统的功能,并处理facade对象指派的任务。
客户角色client:调用facade角色完成功能。
四、laravel中的facade
Laravel 自带了很多 Facades ,可以访问绝大部分 Laravel 的功能。不管是 Laravel 自带的 Facades,还是用户自定义的 Facades ,都继承自 Illuminate\Support\Facades\Facade 类。
Facade 基类使用了 __callStatic() 魔术方法将你的 Facades 的调用延迟,直到对象从容器中被解析出来。
我们来试着创建一个自己的facade:
1.定义一个类让他继承自Illuminate\Support\Facades\Facade,并且实现一个抽象方法getFacadeAccessor。
use Illuminate\Support\Facades\Facade;
class Example extends Facade
{
/**
* 获取组件注册名称
*
* @return string
*/
protected static function getFacadeAccessor() {
return 'example';
}
}
注意你的 facade 现在只有一个方法,返回了一个字符串 'example' , 这个字符串是一个标号,用来给 laravel 的服务提供者解析使用的。
2.实现example功能。在创建的example.php文件中写上自己用的内容。
<?php
namespace App\Facades\Example;
class Example
{
function example1(){};
function example2(){};
}
3.注册服务
在 app/Providers 下新建 FacadesServiceProvider.php。
<?php
namespace App\Providers;
use App\Service\ApiService;
use Illuminate\Support\ServiceProvider;
// include the class facade binded
use App\Facades\Example;
class FacadesServiceProvider extends ServiceProvider
{
/**
* 在容器中注册绑定。
*
* @return void
*/
public function register()
{
$this->app->singleton('example', function ($app) {
return new Example($app);
});
}
}
在config/app.php 中找到 providers 和 aliases ,将你的服务提供者和 facade 别名配置一下 :
providers 加入 :
App\Providers\FacadeServiceProvider::class,
aliases 加入:
'Example' => App\Facades\Example::class,
4.使用
现在,在任何一个控制器,或者路由的回调函数中,使用
$test = Example::example1();