通过 facade(尤其是 realtime facade)来使代码更优雅 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
pilishen
V2EX    2018

通过 facade(尤其是 realtime facade)来使代码更优雅

  •  
  •   pilishen 2018-02-02 21:55:01 +08:00 1617 次点击
    这是一个创建于 2881 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文来自 pilishen.com----原文链接

    该篇翻译整理自 laravel 创始人 Taylor 的文章:Expressive Code & Real Time Facades,属于《 Laravel 底层核心技术实战揭秘》这一课程《 laravel 底层核心概念解析》这一章的扩展阅读。

    laravel 5.4 引入了 realtime facade 的功能,也即任何一个 class 都可以随时拿来当 facade 用,只要在其 namespace 前面加上 Facades 前缀即可。当然这个功能不可能随处都用到,但是偶尔呢,用它可以实现更简洁优雅、易于测试的代码方案。虽然下面的例子讲的是 laravel 5.4 的 realtime facade,但是呢,其实也完全可以用在之前的版本上,因为所谓的 realtime facade,无非就是系统自动给你注册成 facade 而已,鉴于这个功能又不可能到处用到,所以即使在老的版本里,如果你发现 facade 的这种代码实现方式更有吸引力,那么自己手动注册一个 facade 也完全可以的。

    接下来的示例是关于 Laravel Forge 的,laravel Forge 是 laravel 官方推出的 laravel 项目部署管理平台。当使用 Forge 的时候,你得在 Forge 后台将你服务器提供商的账号信息填上,然后呢交由 Forge 来具体管理。那么,这里假设呢我们有一个 Model 叫 Provider,也就是对应着不同的主机提供商,比如国外的 DigitalOcean、国内的阿里云等。

    <?php use App; use Illuminate\Database\Eloquent\Model; class Provider extends Model { // } 

    这里呢假设我们将所有处理外来 API 请求的 class 放在App\Services文件夹下,我们得对应每一个主机供应商都有一个“ service ” class,假设 DigitalOcean 这家供应商的 service class 是这样的:

    <?php namespace App\Services; use App\Contracts\ServerProvider; class DigitalOcean implements ServerProvider { public function createServer($name, $size) { // } } 

    接下来呢,我们得能够解析这个服务类,基于我们 model 里的 type 这一栏的信息,我们可以使用工厂( factory )模式来实现:

    <?php namespace App\Services; use InvalidArgumentException; class ServerProviderFactory { public function make($type) { switch ($type) { case 'DigitalOcean': return new DigitalOcean; case 'Linode': return new Linode; default: throw new InvalidArgumentException; } } } 

    然后呢,我们就可以在需要的地方调用这个工厂,来相应地创建一个 server 服务,比如假设在 controller 里调用:

    <?php namespace App\Http\Controllers; use App\Provider; use Illuminate\Http\Request; use App\Services\ServerProviderFactory; class ServerController extends Controller { protected $factory; public function __construct(ServerProviderFactory $factory) { $this->factory = $factory; } public function store(Request $request, Provider $provider) { $service = $this->factory->make($provider->type); $respOnse= $service->createServer($request->name, $request->size); // } } 

    但是呢,我觉得这样还是有些繁琐,我想要是这样来用该多好呢?

    <?php namespace App\Http\Controllers; use App\Provider; use Illuminate\Http\Request; class ServerController extends Controller { public function store(Request $request, Provider $provider) { $repsOnse= $provider->service()->createServer( $request->name, $request->size ); // } } 

    我们只想简单地调用Provider这个实例上的service方法,然后就能获取到其背后对应的供应商,然后就能直接地createServer。这样来写呢,可能更像是我们日常中最直接的思考过程,虽然可能背后具体怎么实现你还没搞懂。那么怎么来实现呢?假设不借助 facade,我们或许可以这样:

    <?php namespace App; use App\Services\ServerProviderFactory; use Illuminate\Database\Eloquent\Model; class Provider extends Model { public function service() { return (new ServerProviderFactory)->make($this->type); } } 

    貌似可行。但是这样呢,因为这个 factory 类是直接在service方法内部实例化的,这是不好的,后期我们无法用它来 mock 测试。那么如果用 realtime facade 的方式会怎么样呢?

    <?php namespace App; use Illuminate\Database\Eloquent\Model; use Facades\App\Services\ServerProviderFactory; class Provider extends Model { public function service() { return ServerProviderFactory::make($this->type); } } 

    现在,不仅看起来更简洁优雅,而且也可以测试了,因为 facade 可以进行 mock,比如说这样:

    <?php namespace Tests\Feature; use Mockery; use App\Provider; use Tests\TestCase; use App\Contracts\ServerProvider; use Facades\App\Services\ServerProviderFactory; use Illuminate\Foundation\Testing\RefreshDatabase; class ExampleTest extends TestCase { public function testBasicTest() { $provider = factory(Provider::class)->create([ 'id' => 1, 'type' => 'DigitalOcean', ]); $service = Mockery::mock(ServerProvider::class); ServerProviderFactory::shouldReceive('make') ->with('DigitalOcean') ->andReturn($service); $service->shouldReceive('createServer') ->once() ->with('web', '2GB') ->andReturn('server-id'); $respOnse= $this->json('POST', '/api/providers/1/server', [ 'name' => 'web', 'size' => '2GB', ]); $response->assertStatus(201); } } 

    你会发现 real-time facade 最有用的地方就是构建简洁、优雅的 object APIs,同时呢又不会影响到代码的可测试性。希望这能给你的实际开发带来一定启发。

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1205 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 17:33 PVG 01:33 LAX 09:33 JFK 12:33
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86