Facade模式

描述:Facade模式要求一个子系统的外部与其内部的通信必须通过一个统一的Facade对象进行。Facade模式提供一个高层次的接口,使得子系统更易于使用。

意义:将一个系统划分成为若干个子系统有利于降低系统的复杂性。一个常见的设计目标是使子系统间的通信和相互依赖关系达到最小。

实现原理

工作流程图

浅析laravel门面原理与实现

业务中需要使用子系统的能力步骤:

1.调用子系统的访问门面,获取相关服务;
2.门面从容器中获取子系统的实例;
3.通过子系统的实例,调用其相关服务。

相关技术点分析:

1.了解facade模式。
2.调用子系统门面中不可访问的方法,会自动触发__callstatic
如 \App\Facade\Redis::set(.....);
3.static 静态延时绑定。参考:PHP后期静态绑定
4.Closure 匿名函数的运用,只有调用$closure()才开始真正起作用。
5.容器的实现。

代码实现

目录结构

浅析laravel门面原理与实现

\client.php 业务调用客户端:

<?php
/**
 * Created by PhpStorm.
 * User: zhangrenjie
 * Date: 2019/1/12
 */
namespace App;
require_once './InitIoc.php';
require_once './Facade.php';
require_once './Facade/Redis.php';

use App\Facade\Redis;

Redis::set('a','b');
echo PHP_EOL;

\Facade.php 门面类

<?php
/**
 * Created by PhpStorm.
 * User: zhangrenjie
 * Date: 2019/1/12
 * Time: 上午11:04
 */
namespace App;

use App\Ioc;

class Facade
{
    public static function getFacadeRoot()
    {
        $facadeAccessor = static::getFacadeAccessor();
        $obj = Ioc::resolve($facadeAccessor);
        return $obj();
    }

    /**
     *
     * @param string $name
     * @param array $arguments
     * @return mixed
     */
    public static function __callStatic(string $name, array $arguments)
    {

        $instance = static::getFacadeRoot();

        if (! $instance) {
            throw new RuntimeException('A facade root has not been set.');
        }
        return $instance->$name(...$arguments);
    }
}

\Facede\Redis.php 访问子系统能力的门面

<?php
/**
 * Created by PhpStorm.
 * User: zhangrenjie
 * Date: 2019/1/12
 * Time: 上午11:07
 */
namespace App\Facade;
//require_once '../Facade.php';

use App\Facade;

class Redis extends Facade
{
    public static function getFacadeAccessor():string
    {
        return 'redis';
    }
}

\Ioc.php服务容器

<?php
/**
 * Created by PhpStorm.
 * User: zhangrenjie
 * Date: 2019/1/12
 * Time: 上午11:22
 */
namespace App;

class Ioc
{
    public static $instance = [];

    /**
     * 注入容器
     * @param string $name
     * @param \Closure $closure
     */
    public static function register(string $name,\Closure $reslove)
    {
        static::$instance[$name]=$reslove;
    }

    /**
     * 返回实例
     * @param string $name
     * @return mixed
     */
    public static function resolve(string $name){
        if(static::$instance[$name] instanceof \Closure){
            return static::$instance[$name];
        }else{
            new $name;
        }
    }
}

\Subsystem\Redis.php 子系统服务能力类

<?php
/**
 * Created by PhpStorm.
 * User: zhangrenjie
 * Date: 2019/1/12
 * Time: 下午12:07
 */
namespace App\Subsystem;

class Redis
{
    public static function set(){
        echo "Hello world";
    }
}

\InitIoc.php 将子系统的实例注入到容器

<?php
/**
 * Created by PhpStorm.
 * User: zhangrenjie
 * Date: 2019/1/12
 * Time: 下午1:45
 */
namespace App;
require_once './Subsystem/Redis.php';
require_once './Ioc.php';

use App\Subsystem\Redis;
use App\Ioc;

//将Redis连接注入容器
Ioc::register('redis',function(){
    return new Redis();
});