简析IoC控制反转

简析IoC控制反转

设计模式原则

  1. 开闭原则:开放扩展,关闭修改。主要将的就是抽象化
  2. 里氏代换替换原则:任何基类能够出现的地方,子类必定能够出现。
  3. 依赖倒转原则:尽可能依赖抽象接口编程而不要去依赖具体实例。🌟
  4. 接口隔离原则:使用多个隔离的接口要好过单个接口。
  5. 迪米特原则:一个实例尽可能少知道与其余实例之间的相互做用关系,使功能模块相对独立。
  6. 合成复用原则:尽可能使用聚合和组合,少用依赖。🌟

什么是IoC

控制反转(简称IoC),是一种面向对象的设计思想,用来下降代码间的耦合度。经过控制反转,对象在被建立的时候,由一个调控系统内全部对象的外界实体,将其所依赖的对象的引用传递给它。也就是将依赖被注入到要调用的对象中。控制反转通常和容器思想结合使用,Ioc就是将对象交给容器去控制,而不是在对象内部直接控制,主要是控制对象的内部依赖。

php

  • 谁控制谁

IoC经过一个专门的容器来建立对象,经过IoC容器来控制对象laravel

  • 控制什么

控制实例的外部依赖编程

  • 关于反转设计模式

    • 正转:由对象去主动获取本身须要的依赖,并控制依赖叫正转
    • 反转:由new对象的容器去获取并建立依赖,对象被动接受依赖,从而组合成一个具备具体功能的实例。



IoC的做用

IoC是一种面向对象的变成思想和指导准则。解决传统控制正转开发中在类内部主动建立依赖类,从而致使类的内部耦合,难以复用。IoC把查找建立依赖的控制权反转给容器,由容器进行注入来组合建立一个对象,不一样需求容器能够注入不一样的对象,从而消除对象和依赖的耦合。数组

IoC思想的实现

DI依赖注入

依赖注入指容器在运行中动态的将依赖注入到组件中,从而使组件具备具体的功能。经过依赖注入能够在特殊的地方指定同一个抽象方法去处理不一样依赖对象的逻辑,而不须要了解和修改具体抽象方法的实现,只须要关注本身的业务层。框架

  • 谁依赖谁

实例化类依赖控制容器函数

  • 为何要依赖

实例化类须要依赖其余资源才能够处理具体业务this

  • 谁注入谁

IoC容器向实例化类中注入了某个依赖spa

  • 注入了什么

实例化类须要处理的依赖对象
设计

如何实现

  • 基于构造函数。实现特定参数的构造函数,在新建对象时传入所依赖类型的对象。
  • 基于接口。实现特定接口以供外部容器注入所依赖类型的对象。
  • 基于 set 方法。实现特定属性的 public set 方法,来让外部容器调用传入所依赖类型的对象。
interface Way
{
    public function go();
}

class GoShanghai
{
    private $charger;

    public function __construct(Way $charger)
    {
        $this->charger = $charger;
    }

        public function setWay(Way $way)
    {
        $this->way = $way;
    }

    public function go()
    {
        $this->charger->go();
    }

}

class Car implements Way
{
    public function go()
    {
        // TODO: Implement go() method.
        print_r("我经过开车去上海");
    }
}
// 基于构造函数和接口
$goshanghai = new GoShanghai(new Car());
$goshanghai->go();
// 基于set方法|展现须要由于构造函数运行会出错
$goshanghai = new GoShanghai();
$goshanghai->setWay(new Car());
$goshanghai->go();

依赖查找

依赖查找更加主动,在须要的时候经过调用框架提供的方法来获取对象,获取时须要提供相关的配置文件路径、key等信息来肯定获取对象的状态。

实现IoC的设计模式

OP观察者模式

观察者模式主要用于处理对象直接一对多多关系。当外部资源发生改变,观察者会获得通知。观察者和被观察者直接是抽象耦合的,也就不影响实例的解藕。

  • 什么是观察者

观察者是一对多关系中的多,观察者须要根据目标对象改变而改变的对象。

  • 观察什么

观察目标对象的某些特定的状态。

  • 如何观察

观察者继承自一个抽象观察类,抽象观察类实现注册、监听和通知功能。

如何实现

observer_pattern_uml_diagram.jpg

/**
 * 观察者的抽象类
 */
abstract class Observer
{
    // 这是一个目标类
    protected $subject;

    // 定义一个用于更新的抽象方法
    public abstract function update();
}

/**
 * 目标类
 */
class Subject {

    // 观察者数组集合
    private $observerList = array();

    // 状态,这里遵循开闭原则将属性私有化
    private $state = 0;

    /**
     * 获取状态的值
     */
    public function getState() :int
    {
        return $this->state;
    }

    /**
     * 设置状态的值
     * @param int $state
     */
    public function setState(int $state)
    {
        $this->state = $state;
        $this->notifyAllObservers();
    }

    /**
     * 注册观察者
     * @param Observer $observer
     */
    public function attach(Observer $observer)
    {
        array_push($this->observerList, $observer);
    }

    /**
     * 通知观察者
     */
    public function notifyAllObservers()
    {
        foreach ($this->observerList as $observer) {
            $observer->update();
        }
    }
}

/**
 * 观察者A
 */
class AObserver extends Observer
{
    public function __construct(Subject $subject)
    {
        // 注入目标依赖实现IoC
        $this->subject = $subject;

        // 注册观察者
        $this->subject->attach($this);
    }

    public function update()
    {
        // TODO: Implement update() method.
        print_r("A观察者更新了支付业务的状态:{$this->subject->getState()}\n");
    }
}
// 建立一个目标对象
$subject = new Subject();

// 为目标对象绑定观察者
new AObserver($subject);

print_r("目标对象的状态:{$subject->getState()}\n");
$subject->setState(10);

// 目标对象的状态:0
// A观察者更新了支付业务的状态:10

TP模版模式

经过一个抽象基类定义执行它的模版也能够是方法,子类重写抽象方法的实现,但调用实在抽象基类中完成的,从而实现控制反转。就是基类控制行为,子类完成实现。

如何实现

template_pattern_uml_diagram.jpg

/**
 * 抽象模版类
 */
abstract class Template
{
    // 抽象方法A
    public abstract function stepA();

    // 抽象方法B
    public abstract function stepB();

    // 执行定义的步骤, 这里使用了final关键字修饰,final的做用是使这个方法不可被继承, 这样就不会被子类执行
    public final function run()
    {
        $this->stepA();
        $this->stepB();
    }
}

/**
 * 方案A的实例
 */
class FuncA extends Template
{
    public function stepA()
    {
        // TODO: Implement stepA() method.
        print_r("方案A第一步\n");
    }

    public function stepB()
    {
        // TODO: Implement stepB() method.
        print_r("方案A第二步\n");
    }
}
$funca = new FuncA();
$funca->run();

Laravel中的IoC

上面的例子能够看到控制反转使每一个业务实例相对对立,他们的组装在代码执行时完成,当业务简单、依赖单一时看上去没有问题,可是当依赖复杂时会致使组装变得繁琐且难以梳理。在laravel中是经过容器Container来解决这个问题。下面咱们经过几句话来简单看一下laravel中容器的使用。

  • 启动laravel时就是启动了一个容器
  • 容器内的实例在一次应用程序级调用中是单例的
  • 经过make实现自动序列化依赖对象,代替new
  • 经过bind方法让每个抽象接口和它的实例类一一对应
  • 经过resolveing方法注册一个回调callback在绑定的对象解析完以后调用
相关文章
相关标签/搜索