外观模式
01 Facade定义
外观模式(又称门面模式) 是一种结构型设计模式,能为程序库、框架或其他复杂类提供一个简单的接口。
在业务实现中,我们经常会用到某各复杂库或框架内众多对象,同时,再加上业务逻辑,代码会变得庞大且难以维护。
如果应用外观模式,提供简单的接口,即可降低整个系统复杂度,为客户端减负。
02 需求场景
当你想看一场网络足球赛事,你需要打开路由器连接网络,以及电视接受信号,这时天气燥热,你可能还会打开空调纳凉。
整个操作较长,可能等你逐一操作完成,球赛已经过去了几分钟,其次,你需要熟悉每个设备操作方法,特定条件下,对你操作顺序也有要求,比如拉闸通电。 :(
如果有一个万能遥控器,一键操作上述电器开启/关闭,是不是很酷~ :)
03 实现“万能遥控器”
<?php
class Facade
{
protected $router; //路由器
protected $tv; //电视
protected $airconditioning //空调
public function __construct(
Router $router = null,
TV $tv = null,
AirConditioning $airC = null
) {
$this->router = $router ?: new Router;
$this->tv = $tv ?: new TV;
$this->airC = $airC ?: new AirConditioning;
}
/**
* 提供简单接口,实现开启操作
*/
public function operationOn(): string
{
$result = "watch the game online:\n";
$result .= $this->router->operationOn();
$result .= $this->tv->operationOn();
$result .= $this->airC->operationOn();
return $result;
}
/**
* 提供简单接口,实现关闭操作
*/
public function operationOff(): string
{
$result = "End of the game,sleep:\n";
$result .= $this->router->operationOff();
$result .= $this->tv->operationOff();
$result .= $this->airC->operationOff();
return $result;
}
}
class Router
{
public function operationOn(): string
{
return "router: on!\n";
}
public function operationOff(): string
{
return "router: off!\n";
}
}
class TV
{
public function operationOn(): string
{
return "TV: on!\n";
}
public function operationOff(): string
{
return "TV: off!\n";
}
}
class AirConditioning
{
public function operationOn(): string
{
return "AirConditioning: on!\n";
}
public function operationOff(): string
{
return "AirConditioning: off!\n";
}
}
function clientCode(Facade $facade)
{
echo $facade->operationOn();
echo $facade->operationOff();
}
$Router = new Router;
$TV = new TV;
$AirConditioning = new AirConditioning;
$facade = new Facade($Router, $TV, $Airconditioning);
//这里选用函数调用,也可以再客户端对象调用
clientCode($facade);
- 客户端对象独立众多子类之外,子类升级,只需要修改facade中的子类
- facade可能会随着复杂度提升,变得臃肿,那么我们可以新专用门面类
laravel中外观模式
Laravel中Router、File、Redis、Log等都有用到外观模式
01 框架应用
- 引入Redis、DB门面类
- 通过静态调用,获取数据
我们再laravel框架中,通过上述进行类调用,那么他们在底层如何运行的呢?
02 外观组件及加载
外观组件的配置数据,同 Laravel 其它服务一样被定义在 config/app.php 文件中。
- 外观配置定义格式遵循 「别名」:「外观类」 的数据格式。
当一个 HTTP 请求被接收时,将在处理请求阶段将这些「外观」组件加载到服务中。
加载工作由定义在 Illuminate\Foundation\Http\Kernel 内核中的 \Illuminate\Foundation\Bootstrap\RegisterFacades::class 启动程序完成
- 首先从配置文件 config/app.php 中读取所有外观服务配置 aliases;
- 然后,读取别名服务$app->make(PackageManifest::class)->aliases();
- 合并两项,注入到AliasLoader对象中去,完成注册
03 探秘Facade实现
我们以DB外观模式为例,这里只是简单的getFacadeAccessor()方法,返回"db"名
回到Facade基类中,我们发现并没有make方法,需要通过__callStatic魔术方法进行回调:
最终是通过Laravel的容器机制把DB的实际对象解析了出来。
04 Facade优势
复杂系统中,过多的子类和模块耦合,极大增加了系统复杂度和维护成本。
虽然整个框架实现facade增加了一定代码量,但是理解之后,框架脉络还是很清晰的,facade应用,也使得类的调用与框架优雅的解耦。
参考资料:
《深入浅出之laravel外观系统》柳公子