成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

IOC 模式解耦與 Laravel 服務(wù)容器

韓冰 / 3127人閱讀

摘要:的優(yōu)美得益于開發(fā)的組件式解耦,這與服務(wù)容器和服務(wù)提供者的理念是離不開的,下篇將用框架中類來梳理服務(wù)容器的工作流程。

原文:blog,轉(zhuǎn)載注明來源即可。
本文代碼:GitHub

前言

服務(wù)容器是 Laravel 框架實(shí)現(xiàn)模塊化解耦的核心。模塊化即是將系統(tǒng)拆成多個(gè)子模塊,子模塊間的耦合程度盡可能的低,代碼中盡可能的避免直接調(diào)用。這樣才能提高系統(tǒng)的代碼重用性、可維護(hù)性、擴(kuò)展性。

下邊出行例子有火車、飛機(jī)兩種出行方式,對(duì)應(yīng)給出了 3 種耦合度越來越低的實(shí)現(xiàn):高度耦合實(shí)現(xiàn)、工廠模式解耦、IOC 模式解耦。

高度耦合實(shí)現(xiàn) 代碼實(shí)現(xiàn)

定義 TrafficTool 接口并用 Train、Plane 實(shí)現(xiàn),最后在 Traveler 中實(shí)例化出行工具后說走就走。代碼十分簡(jiǎn)潔:

travelTool = new Train();
    }

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


$me = new Traveler();
$me->travel();

運(yùn)行:

$ php normal.php
[Travel By]: train
優(yōu)點(diǎn)

代碼十分簡(jiǎn)潔:一個(gè)接口兩個(gè)類最后直接調(diào)用。

缺點(diǎn)

在第 32 行,TravelerTrain 兩個(gè)組件發(fā)生了耦合。以后想坐飛機(jī)出行,必須修改 __construct() 的內(nèi)部實(shí)現(xiàn):$this->travelTool = new Plane();

重用性和可維護(hù)性都很差:在實(shí)際的軟件開發(fā)中,代碼會(huì)根據(jù)業(yè)務(wù)需求的變化而不斷修改。如果組件之間直接相互調(diào)用,那組件的代碼就不能輕易修改,以免調(diào)用它的地方出現(xiàn)錯(cuò)誤。

工廠模式解耦 工廠模式

分離代碼中不變和變的部分,使得在不同條件下創(chuàng)建不同的對(duì)象。

代碼實(shí)現(xiàn)
...

class  TrafficToolFactory
{
    public function create($name) {
        switch ($name) {
            case "train":
                return new Train();
            case "plane":
                return new Plane();
            default:
                exit("[No Traffic Tool] :" . $name);
        }
    }
}


// 旅游者類,使用火車出行
class Traveler
{
    protected $trafficTool;

    public function __construct($toolName) {
        // 使用工廠類實(shí)例化需要的交通工具
        $factory = new TrafficToolFactory();
        $this->travelTool = $factory->create($toolName);
    }

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

// 傳入指定的方式
$me = new Traveler("train");
$me->travel();

運(yùn)行:

$ php factory.php
[Travel By]: train
優(yōu)點(diǎn)

提取了代碼中變化的部分:更換交通工具,坐飛機(jī)出行直接修改 $me = new Traveler("plane") 即可。適用于需求簡(jiǎn)單的情況。

缺點(diǎn)

依舊沒有徹底解決依賴:現(xiàn)在 TravelerTrafficToolFactory 發(fā)生了依賴。當(dāng)需求增多后,工廠的 switch...case 等代碼也不易維護(hù)。

IOC 模式解耦

IOC 是 Inversion Of Controll 的縮寫,即控制反轉(zhuǎn)。這里的“反轉(zhuǎn)”可理解為將組件間依賴關(guān)系提到外部管理。

簡(jiǎn)單的依賴注入

依賴注入是 IOC 的一種實(shí)現(xiàn)方式,是指組件間的依賴通過外部參數(shù)(interface)形式直接注入。比如對(duì)上邊的工廠模式進(jìn)一步解耦:

trafficTool = $tool;
    }

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

$train = new Train();
$me    = new Traveler($train);    // 將依賴直接以參數(shù)的形式注入
$me->travel();

運(yùn)行:

$ php simple_ioc.php
[Travel By]: train
高級(jí)依賴注入 簡(jiǎn)單注入的問題

如果三個(gè)人分別自駕游、坐飛機(jī)、高鐵出去玩,那你的代碼可能是這樣的:

$train = new Train();
$plane = new Plane();
$car   = new Car();

$a = new Traveler($car);
$b = new Traveler($plane);
$c = new Traveler($train);

$a->travel();
$b->travel();
$c->travel();

看起來就兩個(gè)字:藍(lán)瘦。上邊簡(jiǎn)單的依賴注入相比工廠模式已經(jīng)解耦挺多了,參考 Laravel 中服務(wù)容器的概念,還能繼續(xù)解耦。將會(huì)使用到 PHP 反射和匿名函數(shù),參考:Laravel 框架中常用的 PHP 語法

IOC 容器

高級(jí)依賴注入 = 簡(jiǎn)單依賴注入 + IOC 容器

binds[$abstract] = $concrete;
        } else {
            $this->instances[$abstract] = $concrete;
        }
    }

    /**
     * 生產(chǎn):執(zhí)行回調(diào)函數(shù)
     *
     * @param $abstract     字符指令
     * @param array $params 回調(diào)函數(shù)所需參數(shù)
     * @return mixed        回調(diào)函數(shù)的返回值
     */
    public function make($abstract, $params = []) {
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        // 此時(shí) $this 是有 2 個(gè)元素的數(shù)組
        // Array (
        //     [0] => Container Object (
        //                [binds] => Array ( ... )
        //                [instances] => Array()
        //            )
        //     [1] => "train"
        // )
        array_unshift($params, $this);

        // 將參數(shù)傳遞給回調(diào)函數(shù)
        return call_user_func_array($this->binds[$abstract], $params);
    }
}

$container = new Container();
$container->bind("traveler", function ($container, $trafficTool) {
    return new Traveler($container->make($trafficTool));
});

$container->bind("train", function ($container) {
    return new Train();
});

$container->bind("plane", function ($container) {
    return new Plane();
});

$me = $container->make("traveler", ["train"]);
$me->travel();

運(yùn)行:

$ php advanced_ioc.php
[Travel By]: train
簡(jiǎn)化并解耦后的代碼

那三個(gè)人再出去玩,代碼將簡(jiǎn)化為:

$a = $container->make("traveler", ["car"]);
$b = $container->make("traveler", ["train"]);
$c = $container->make("traveler", ["plane"]);

$a->travel();
$b->travel();
$c->travel();

更多參考:神奇的服務(wù)容器

Laravel 的服務(wù)容器

Laravel 自己的服務(wù)容器是一個(gè)更加高級(jí)的 IOC 容器,它的簡(jiǎn)化代碼如下:

getClosure($abstract, $concrete);
        }
        $this->binds[$abstract] = compact("concrete", "shared");
    }

    // 獲取回調(diào)函數(shù)
    public function getClosure($abstract, $concrete) {
        return function ($container) use ($abstract, $concrete) {
            $method = ($abstract == $concrete) ? "build" : "make";
            return $container->$method($concrete);
        };
    }

    protected function getConcrete($abstract) {
        if (!isset($this->binds[$abstract])) {
            return $abstract;
        }
        return $this->binds[$abstract]["concrete"];
    }


    // 生成實(shí)例對(duì)象
    public function make($abstract) {
        $concrete = $this->getConcrete($abstract);
        if ($this->isBuildable($abstract, $concrete)) {
            $obj = $this->build($concrete);
        } else {
            $obj = $this->make($concrete);
        }
        return $obj;
    }


    // 判斷是否要用反射來實(shí)例化
    protected function isBuildable($abstract, $concrete) {
        return $concrete == $abstract || $concrete instanceof Closure;
    }

    // 通過反射來實(shí)例化 $concrete 的對(duì)象
    public function build($concrete) {
        if ($concrete instanceof Closure) {
            return $concrete($this);
        }
        $reflector = new ReflectionClass($concrete);
        if (!$reflector->isInstantiable()) {
            echo "[can"t instantiable]: " . $concrete;
        }

        $constructor = $reflector->getConstructor();
        // 使用默認(rèn)的構(gòu)造函數(shù)
        if (is_null($constructor)) {
            return new $concrete;
        }

        $refParams = $constructor->getParameters();
        $instances = $this->getDependencies($refParams);
        return $reflector->newInstanceArgs($instances);
    }


    // 獲取實(shí)例化對(duì)象時(shí)所需的參數(shù)
    public function getDependencies($refParams) {
        $deps = [];
        foreach ($refParams as $refParam) {
            $dep = $refParam->getClass();
            if (is_null($dep)) {
                $deps[] = null;
            } else {
                $deps[] = $this->resolveClass($refParam);
            }
        }
        return (array)$deps;
    }

    // 獲取參數(shù)的類型類名字
    public function resolveClass(ReflectionParameter $refParam) {
        return $this->make($refParam->getClass()->name);
    }
}


$container = new Container();

// 將 traveller 對(duì)接到 Train 
$container->bind("TrafficTool", "Train");
$container->bind("traveller", "Traveller");

// 創(chuàng)建 traveller 實(shí)例
$me = $container->make("traveller");
$me->travel();

運(yùn)行:

$ php laravel_ioc.php     
[Travel By]: train

Train 類要能被實(shí)例化,需要先注冊(cè)到容器,這就涉及到 Laravel 中服務(wù)提供者(Service Provider)的概念了。至于服務(wù)提供者是怎么注冊(cè)類、注冊(cè)之后如何實(shí)例化、實(shí)例化后如何調(diào)用的... 下節(jié)詳細(xì)分析。

總結(jié)

本文用一個(gè)旅游出行的 demo,引出了高度耦合的直接實(shí)現(xiàn)、工廠模式解耦和 IOC 模式解耦共計(jì)三種實(shí)現(xiàn)方式,越往后代碼量越多還有些繞,但類(模塊)之間的耦合度越來越低,最后實(shí)現(xiàn)了簡(jiǎn)化版的 Laravel 服務(wù)容器。

Laravel 的優(yōu)美得益于開發(fā)的組件式解耦,這與服務(wù)容器和服務(wù)提供者的理念是離不開的,下篇將用 Laravel 框架 laravel/framework/src/Illuminate/Container.phpContainer 類來梳理 Laravel 服務(wù)容器的工作流程。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/28798.html

相關(guān)文章

  • Laravel中的核心概念

    摘要:可以為服務(wù)提供者的方法設(shè)置類型提示。方法將在所有其他服務(wù)提供者均已注冊(cè)之后調(diào)用。所有服務(wù)提供者都在配置文件中注冊(cè)??梢赃x擇推遲服務(wù)提供者的注冊(cè),直到真正需要注冊(cè)綁定時(shí),這樣可以提供應(yīng)用程序的性能。 本文最早發(fā)布于 Rootrl的Blog 導(dǎo)言 Laravel是一款先進(jìn)的現(xiàn)代化框架,里面有一些概念非常重要。在上手Laravel之前,我認(rèn)為先弄懂這些概念是很有必要的。你甚至需要重溫下PHP...

    ddongjian0000 評(píng)論0 收藏0
  • 詳解 Laravel 中的依賴注入和 IoC

    摘要:依賴注入依賴注入一詞是由提出的術(shù)語,它是將組件注入到應(yīng)用程序中的一種行為。就像說的依賴注入是敏捷架構(gòu)中關(guān)鍵元素。類依賴于,所以我們的代碼可能是這樣的創(chuàng)建一個(gè)這是一種經(jīng)典的方法,讓我們從使用構(gòu)造函數(shù)注入開始。 showImg(https://segmentfault.com/img/remote/1460000018806800); 文章轉(zhuǎn)自:https://learnku.com/la...

    haitiancoder 評(píng)論0 收藏0
  • 深入剖析 Laravel 服務(wù)容器

    摘要:劃下重點(diǎn),服務(wù)容器是用于管理類的依賴和執(zhí)行依賴注入的工具。類的實(shí)例化及其依賴的注入,完全由服務(wù)容器自動(dòng)的去完成。 本文首發(fā)于 深入剖析 Laravel 服務(wù)容器,轉(zhuǎn)載請(qǐng)注明出處。喜歡的朋友不要吝嗇你們的贊同,謝謝。 之前在 深度挖掘 Laravel 生命周期 一文中,我們有去探究 Laravel 究竟是如何接收 HTTP 請(qǐng)求,又是如何生成響應(yīng)并最終呈現(xiàn)給用戶的工作原理。 本章將帶領(lǐng)大...

    abson 評(píng)論0 收藏0
  • php實(shí)現(xiàn)依賴注入(DI)和控制反轉(zhuǎn)(IOC)

    摘要:工廠模式,依賴轉(zhuǎn)移當(dāng)然,實(shí)現(xiàn)控制反轉(zhuǎn)的方法有幾種。其實(shí)我們稍微改造一下這個(gè)類,你就明白,工廠類的真正意義和價(jià)值了。雖然如此,工廠模式依舊十分優(yōu)秀,并且適用于絕大多數(shù)情況。 此篇文章轉(zhuǎn)載自laravel-china,chongyi的文章https://laravel-china.org/top...原文地址: http://www.insp.top/learn-lar... ,轉(zhuǎn)載務(wù)必保...

    tomato 評(píng)論0 收藏0
  • 深入理解控制反轉(zhuǎn)(IoC)和依賴注入(DI)

    摘要:本文一大半內(nèi)容都是通過舉例來讓讀者去理解什么是控制反轉(zhuǎn)和依賴注入,通過理解這些概念,來更加深入。這種由外部負(fù)責(zé)其依賴需求的行為,我們可以稱其為控制反轉(zhuǎn)。工廠模式,依賴轉(zhuǎn)移當(dāng)然,實(shí)現(xiàn)控制反轉(zhuǎn)的方法有幾種。 容器,字面上理解就是裝東西的東西。常見的變量、對(duì)象屬性等都可以算是容器。一個(gè)容器能夠裝什么,全部取決于你對(duì)該容器的定義。當(dāng)然,有這樣一種容器,它存放的不是文本、數(shù)值,而是對(duì)象、對(duì)象的描...

    HollisChuang 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<