用Martin Fowler的话最好地定义软件设计模式:
模式提供了一种以参考格式呈现设计建议的机制。 软件设计是一个巨大的主题,当遇到设计问题时,您必须能够专注于尽可能解决问题的事物。
采用设计模式的代码易于理解,维护和扩展。 本教程的目的是在Laravel中推广外观。
什么是立面模式?
根据“四人帮”的定义, 立面设计模式是一种结构模式,它定义了到更复杂子系统的简化接口。 该模式基于在所需逻辑和方法的集合前面创建一个简单的外观界面。 外观本身维护相关性。
外观与适配器和装饰器图案非常相似。 适配器的作用就像是两个不兼容的接口之间的桥梁,而装饰器则更为复杂,并用于动态更改对象的行为。
什么是Laravel外墙?
Laravel使用的甜美语法使编写代码更简洁,更易于理解。 Laravel外墙实际上是服务位置的语法糖 。
让我们看一下Laravel Facade及其功能方式。 Laravel中的Cache
外观如下所示:
Cache::get('key');
尽管看上去似乎正在使用大量静态方法,但是Laravel实际上提供了一个接口,该接口指向应用程序的服务容器中可用的类。 您可能已经知道,以上编写的代码等效于:
$app = app();
$app->make('cache')->get('key');
当Cache外观放置在Cache.php
时,Laravel的外观将对象放置在vendor/Laravel/framework/src/Illuminate/Support/Facades
中:
namespace Illuminate\Support\Facades;
class Cache extends Facade {
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'cache';
}
}
当我们使用cache::get('key')
,实际上是在调用上面的类。 确保在配置文件config /app.php
创建上述类的别名:
'aliases' => [
//...
'Cache'=>Illuminate\Support\Facades\Cache::class,
别名由Laravel自动加载程序自动设置。 将类的名称设置为缓存可创建与外观的一致性。 这个选项肯定会使使用Facade的人对您的代码更加满意。
以下三种方法对于生成立面至关重要:
- __callStatic() PHP魔术方法,在子类中定义为
getFacadeAccessor
方法。 - Facade根,代表Facade调用方法的基础类。
-
resolveFacadeInstance
方法负责解析服务的正确实例。
Facade类方法的实现:
//...
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
switch (count($args))
{
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
default:
return call_user_func_array(array($instance, $method), $args);
}
}
__callStatic
基本上调用IoC容器与该类绑定。 它还通过PHP call_user_func_array()
函数使用切换条件来调用其(非静态)方法,并将参数数组传递给返回对象getFacadeRoot()
方法。 getFacadeRoot()
方法如下所示:
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(
static::getFacadeAccessor()
);
}
和resolveFacadeInstance()
:
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) returns $name;
if (isset(static::$resolvedInstance[$name]))
{
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
如本文最后一行所述,在resolveFacadeInstance
,Laravel返回服务定位器的实例。 由于定位器是原始类的纯实例,因此我们得出结论,Laravel外墙与GoF的外墙模式定义不匹配。 这些只是服务位置。 与Laravel门面不同,由于创建了硬编码的依赖关系,Real Facade使编写单元测试变得困难,有时甚至是不可能。
对于那些认为通过构造函数进行DI比使用Laravel Facade是更好的选择的人,我想告诉您可能包括一些额外的配置。
如何创建Laravel外立面
我想创建一个检查文件Laravel Facade,它负责检查输入文件是否为pdf。 为此,首先我们需要在App/MyFacade/IsPdf.php
创建Is Pdf
类:
namespace App\MyFacade;
class IsPdf
{
private $pdf = "\x25\x50\x44\x46\x2D";
public function check($file)
{
return (file_get_contents($file, false, null, 0, strlen($this->pdf)) === $this->pdf) ? true : false;
}
}
其次,将类绑定到服务提供者。 您将创建新的服务提供商,该服务提供商位于App\Providers\IsPdfServiceProvider:
namespace App\Providers;
use Illuminate\Support\Facades\App;
use Illuminate\Support\ServiceProvider;
class IsPdfServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
App::bind('IsPdf', function()
{
return new \App\MyFacade\IsPdf;
});
}
}
第三,创建Facade类,作为前面提到的Illuminate\Support\Facades\Facade
类的扩展。 您将创建位于App\Facades\IsPdfFacade.php
。
namespace App\Facades;
use Illuminate\Support\Facades\Facade;
class IsPdf extends Facade{
protected static function getFacadeAccessor() { return 'IsPdf'; }
}
最后一步是在config/app.php:
注册Facade config/app.php:
/*
* Application Service Providers...
*/
App\Providers\IsPdfServiceProvider::class,
和别名:
'IsPdf' => App\Facades\IsPdf::class
恭喜你! 您已经成功创建了Laravel门面。 可以使用一些代码随意测试Facade,例如:
Route::get('/', function(){
IsPdf::check('/files/file.pdf');
});
结论
现在我们知道Laravel外观使调用方法变得非常容易,并且注入实际的依赖关系可以真正付诸实践。 当然,Laravel Facade具有自己的优点和缺点。 取决于开发人员选择正确的选项。
有关Laravel的其他资源,请务必查看市场上的产品 。
谁知道,也许这篇文章会鼓励您开发与框架无关的代码,而不必使用Facade! 祝好运!
翻译自: https://code.tutsplus.com/tutorials/what-are-laravel-50-facades--cms-25347