Contents

依赖注入和控制反转

Prerequisites

代码的作用

  • 程序是写给机器运行的,代码是写给人维护的

封装调用

  • 对于一个程序来说,完全可以写在一个文件中,且从头到尾,需要什么,都直接写,而非封装调用;也就是只通过各个语言编写最基础的cpu指令,比如加减、逻辑运算(或与非等)、流程控制(for|if等),连语言标准库中的函数都不事用
  • 也可以对于重复的代码进行封装,待需要的时候进行调用

优雅的代码

  • 在我看来,代码的优雅至少应该是:基于逻辑性强、可读性强的一种简洁;所以封装是必须的
  • 在封装调用中,就分成了调用方与模块(被调用方);调用方功能的实现是离不开模块的,也就是说调用方是依赖模块的
  • 如何调用这些依赖呢?

依赖注入(Dependency Injection)和控制反转(Inversion Of Control)

  • 在我看来,控制反转就是以细化功能为前提,降低调用方对模块的依赖,不用管模块的实现方式,达到模块自行控制的目的;
  • 依赖注入是控制反转的手段,常用的有构造方法入参,setter方法,这些都是一次性的,就是指不同的调用者调用不同的模块是没有什么优化的
  • 这些模块如果是经常被使用的,比如日志服务,那么这些调用就是属于重复操作了,可以再进一步封装,服务容器就是引入一个中间人,经常使用的那些模块先注册,调用方在用的时候直接获取就行了

laravel中的服务容器

  • laravel的服务容器就是Illuminate\Foundation\Application

常用的模块绑定到服务容器的方式

  • 绑定闭包
1
2
3
$this->app->bind('HelpSpot\API', function ($app) {
    return new HelpSpot\API($app['HttpClient']);
});
  • 绑定单例
1
2
3
$this->app->singleton('FooBar', function ($app) {
    return new FooBar($app['SomethingElse']);
});
  • 绑定实例
1
2
3
$fooBar = new FooBar(new SomethingElse);

$this->app->instance('FooBar', $fooBar);
  • 上下文绑定
1
2
3
4
5
$this->app->when('App\Handlers\Commands\CreateOrderHandler')
        ->needs('App\Contracts\EventPusher')
        ->give(function () {
          // Resolve dependency...
        });

常用的调用方式

1
2
3
4
5
6
7
8
$this->app->make('TestService');
// 或
$this->app['TestService'];
// 或
App::make('reports');
// 传参的话:
$this->app->makeWith(TestService::class, ['id' => 1]);
// 也可以来个facade直接调方法

laravel的服务容器在每一次解析对象时都会触发一个事件,可以使用resolving方法监听该事件

1
2
3
4
5
6
7
$this->app->resolving(function ($object, $app) {
    // 容器解析所有类型对象时调用
});

$this->app->resolving(function (FooBar $fooBar, $app) {
    // 容器解析"FooBar"对象时调用
});

本文参考

coffee