设计模式 7年前

依赖注入、控制反转容器、服务定位器

作者头像 刘宇帅
2756 0

在了解依赖注入和服务定位器之前先了解以下两种模式的思想基础:依赖倒置原则和控制反转

依赖倒置原则(Dependence Inversion Principle,DIP)

定义

  1. 高层次的模块不应该依赖于低层次的模块,两者都应该依赖于抽象接口。
  2. 抽象接口不应该依赖于具体实现。而具体实现则应该依赖于抽象接口。

问题由来
类A直接依赖于类B,假如要将类A改为依赖类C,则必须修改类A的代码来完成,这种场景下一般A类为业务类,而B、C类为底层模块,假如因此修改了A类代码,会给程序带来不必要的风险。
解决方案
将A类修改为依赖接口D,类B和类C分别实现接口D,类A通过接口D和B、C发生关联,这样会大大降低修改类A的概率

控制反转原则(Inversion of Control,IoC)

DIP是一种思想,而IoC是对DIP的一种实现思路,IoC核心思路就是把A类对B、C类的依赖过程交给第三方来管理。即A给地方要依赖,具体给B还是C、怎么实例化都由第三方决定。

依赖注入(Dependece Injection,DI)

依赖注入是对IoC思路的一种模式,按照Di的模式就可以实现 IoC,符合DIP原则,DI 的核心是把类所依赖的类等的实例化过程放到类的外面实现。例如构造函数注入、属性注入、set函数注入等。

控制反转容器(IoC Container)

按照DI的方式实现了依赖注入,但是对于大型项目,如果每个类都是手动去注入就会让系统变得很复杂。而 Ioc Container 就是一个容器,里面包含了各种类的自动创建、并自动注入依赖单元,这样就减少了很多代码量。

服务定位器(Service Location)

服务定位器也是一个容器,里面有基础服务的实例化方式,而且每个类或服务只会实例化一次,共用实例提高性能,而且支持对每个类或服务的实现方式进行修改。

Laravel里的实现

在 laravel 里对控制反转的应用比较多,像门面(Facade)、服务提供者这些都是。我这里大致看了下路由 action 中对其的应用。
一个简单的 hello 的 action 如下

namespace App\\Http\\Controllers;
use Illuminate\\Http\\Request;

class IndexController extends Controller
{
    public function hello(Request $request)
    {
        echo "hello world!";
    }
}

Laravel 里IoC Container 就是 $app (例如 CGI 模式下:Illuminate\Foundation\Application)。上面的controller就是由$app 的 make 函数自动创建的,代码如下

// 类 Illuminate\\Routing\\Route 的源码
public function getController()
    {
        if (! $this->controller) {
            $class = $this->parseControllerCallback()[0];
            // 这里的container就是$app,通过 make 函数实例化 controller
            $this->controller = $this->container->make(ltrim($class, \'\\\\\'));
        }

        return $this->controller;
    }

而 action 所需要的参数是自动注入的,代码如下

// 类 Illuminate\\Routing\\ControllerDispatcher 的源码
public function dispatch(Route $route, $controller, $method)
    {
        // 解析函数依赖的参数,往里跟的话依然可以看到 action 参数实例化同样会用到 Ioc 容器
        $parameters = $this->resolveClassMethodDependencies(
            $route->parametersWithoutNulls(), $controller, $method
        );

        if (method_exists($controller, \'callAction\')) {
            return $controller->callAction($method, $parameters);
        }
        // 传入解析参数并调用
        return $controller->{$method}(...array_values($parameters));
    }
作者头像

刘宇帅

非著名程序员,全栈开发工程师,长期专注系统开发与架构设计。

提示

功能待开通!


暂无评论~

相关文章

golang 设计模式之抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 介绍 意图:提供一个创建一系列相关或则相互依赖对象的接口,而无需指定他们依赖的类。 解决问题:主要解决接口选择的问题 优点:调用方面向接口编程,不用关心具体实现 缺点:扩展新的产品复杂,新增一个新产品需要修改工厂接口和所有工厂类 可应用场景 系统主题:比如一个游戏主题分为男生主题、女生主题 实现 以系统主题为例 结构 代码 游戏颜色 // 颜色接口 type Color interface {

golang 设计模式之简单工厂模式

简单工厂模式(Sample Factory Pattern)是最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。 介绍 意图:提供一个创建对象的工厂,工厂类函数会根据不同的参数创建实现了同一接口的不同产品类。 解决问题:主要解决接口选择的问题 优点 如果要创建一个产品对象只要知道其名字就可以了,不需要关心具体实现 可扩展,只需要实现一个产品类就可以了 缺点 不同的实现都需要实现一个具体的类,提升系统复杂性 新增产品类的时候需要修改创建对象的工厂

设计模式概述

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与