日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
PHP高級(jí)特性:反射與工廠設(shè)計(jì)模式如何結(jié)合使用

php高級(jí)特性-反射以及工廠設(shè)計(jì)模式的結(jié)合使用 [結(jié)合 Laravel-Admin 代碼實(shí)例講解]

利用反射來實(shí)現(xiàn)工廠模式的生產(chǎn)而無需創(chuàng)建特定的工廠類

反射[Relfection]

什么是Reflection

Reflection,即反射。反射提供給面向?qū)ο缶幊炭梢宰允〉哪芰?/p>

這么理解有點(diǎn)太過于概念化,通俗地講,就是能根據(jù)事件的結(jié)果反查出原因。在編程中,可以根據(jù)一個(gè)被實(shí)例化的對(duì)象,反查出這個(gè)對(duì)象屬于的類以及該類擁有所有屬性以及方法,甚至可以讀取文檔注釋。這個(gè)反查的過程就叫做反射【推薦學(xué)習(xí):PHP視頻教程】

PHP 提供了完整的反射 API ,提供了內(nèi)省類、接口、函數(shù)、方法和擴(kuò)展的能力。此外,反射 API 提供了方法來取出函數(shù)、類和方法中的文檔注釋。詳細(xì)見PHP官網(wǎng) PHP反射簡(jiǎn)介

Reflection能干什么

在上面講到的,可以使用反射來獲取一個(gè)類的所有屬性以及方法還有注釋文檔,甚至可以獲取類屬性和方法的訪問權(quán)限[protected/private],這些特性使得PHP的使用靈活性得到非常大的提高。例如:

– Laravel 框架的所謂優(yōu)雅所在,即容器、依賴注入、IOC 控制反轉(zhuǎn)就是依靠這些特性實(shí)現(xiàn)的

– Hyperf 框架的注解路由也是根據(jù)反射獲得注釋來實(shí)現(xiàn)的

– 生成文檔 因?yàn)榉瓷淇梢垣@取類屬性和方法的訪問權(quán)限,可以掃描整個(gè)項(xiàng)目的所有文件再使用反射來生成文檔

– 測(cè)試驅(qū)動(dòng)開發(fā) 利用反射獲取該類的所有方法的特性,進(jìn)行測(cè)試驅(qū)動(dòng)開發(fā)

– 開發(fā)插件 利用反射獲取類的內(nèi)部結(jié)構(gòu)的特性,實(shí)現(xiàn) Hook 功能,例如框架插件的實(shí)現(xiàn)

Reflection的優(yōu)缺點(diǎn)

優(yōu)點(diǎn) 反射提供了對(duì)類的反解析,從而相比原本面向?qū)ο蟮木幊谭绞将@得了極高的靈活性,以及合理的使用能夠讓代碼看起來更加優(yōu)雅以及簡(jiǎn)潔。原本在面向?qū)ο蟮木幊谭绞街?,使用一個(gè)類的實(shí)例需要先 new 出一個(gè)對(duì)象再使用方法,但是使用了反射機(jī)制,只需要提供一個(gè)該類的方法然后使用反射機(jī)制即可使用該對(duì)象或者方法。Laravel 框架正是使用了大量的反射才獲得了優(yōu)雅的美譽(yù),Swoole 的 Hyperf 框架的注解路由的實(shí)現(xiàn)也是使用了反射

缺點(diǎn) 同時(shí),由于反射是類實(shí)例化的反過程,破壞了面向?qū)ο蟮姆庋b性,直接將類的整個(gè)內(nèi)部結(jié)構(gòu)暴露,這就導(dǎo)致了反射一旦濫用,代碼將難于管理,整個(gè)項(xiàng)目將非?;靵y,甚至導(dǎo)致業(yè)務(wù)執(zhí)行錯(cuò)亂。尤其在大項(xiàng)目幾十人的團(tuán)隊(duì)中,試想一下,原本的面向?qū)ο螅桓嬖V什么可以用,什么不可以用,CTO寫好了底層代碼,其他人繼承后然后使用就行,內(nèi)部結(jié)構(gòu)啥的其他人都不知道。一旦用上了反射,如果有一個(gè)程序員不小心將原本是 protected 或者是 private 的屬性或者方法設(shè)置成了可以訪問,其他程序員在不知情的情況調(diào)用了本該隱藏的數(shù)據(jù)或者方法,那將導(dǎo)致不可預(yù)測(cè)的災(zāi)難【見下面示例代碼】

其次,由于反射的靈活性極高,這導(dǎo)致了無法在 IDE 中通過直接直接點(diǎn)擊代碼溯源,對(duì)于新手真的是很蛋疼,Laravel 和Hyperf 都是如此

在下面的代碼中,反射的機(jī)制直接將 private 方法設(shè)置成外部可訪問

#Example:
setAccessible(true);
echo $method->invoke(new Foo);
// echos "7"
?>

工廠設(shè)計(jì)模式

三種工廠設(shè)計(jì)模式 [簡(jiǎn)單工廠模式] [工廠模式] [抽象工廠模式]

簡(jiǎn)單工廠模式 又稱為靜態(tài)工廠方法模式。簡(jiǎn)單的說,就是創(chuàng)建對(duì)象的方式是通過一個(gè)靜態(tài)方法來實(shí)現(xiàn)的。在簡(jiǎn)單工廠模式中,根據(jù)傳遞的參數(shù)來返回不同的類的實(shí)例

在PHP中在簡(jiǎn)單工廠模式中,有一個(gè)抽象的產(chǎn)品類【即abstract class Calculate】,這個(gè)抽象類可以是接口/抽象類/普通類。這個(gè)抽象的產(chǎn)品類可以派生出多個(gè)具體的產(chǎn)品類【即class CalculateAdd以及class CalculateSub】。最后再由一個(gè)具體的工廠類【即class CalculateFactory】來獲取所需要的產(chǎn)品類的實(shí)例

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

1) 抽象產(chǎn)品生產(chǎn)類:運(yùn)算抽象類

//生產(chǎn)抽象類
abstract class Calculate{
    //數(shù)字A
    protected $number_a = null;
    //數(shù)字B
    protected $number_b = null;
    //設(shè)置數(shù)字A
    public function setNumberA( $number ){
        $this->number_a = $number;
    }
    //設(shè)置數(shù)字B
    public function setNumberB( $number ){
        $this->number_b = $number;
    }
    //獲取數(shù)字A
    public function getNumberA(){
        return $this->number_a;
    }
    //獲取數(shù)字B
    public function getNumberB(){
        return $this->number_b;
    }
    //獲取計(jì)算結(jié)果【獲取生產(chǎn)出的產(chǎn)品】
    public function getResult(){
        return null;
    }
}

2) 具體產(chǎn)品生產(chǎn)類:加法運(yùn)算 / 減法運(yùn)算 等等

//加法運(yùn)算
class CalculateAdd extends Calculate{
    //獲取運(yùn)算結(jié)果【獲取具體的產(chǎn)品】
    public function getResult(){
        return $this->number_a + $this->number_b;
    }
}
//減法運(yùn)算
class CalculateSub extends Calculate{
    //獲取運(yùn)算結(jié)果【獲取具體的產(chǎn)品】
    public function getResult(){
        return $this->number_a - $this->number_b;
    }
}
//乘法 / 除法 等等其他運(yùn)算【其他產(chǎn)品】

3) 工廠:工廠類。即用一個(gè)單獨(dú)的類來創(chuàng)造實(shí)例化的過程,這個(gè)類就是工廠。也就是 簡(jiǎn)單工廠模式

在 php 中,實(shí)現(xiàn)的方式其實(shí)就一個(gè) switch 函數(shù)或者是 php8 新出的 match 函數(shù)來實(shí)例化所需要的產(chǎn)品生產(chǎn)類

//根據(jù)運(yùn)算不同實(shí)例化不同的對(duì)象
//【也就是根據(jù)所需產(chǎn)品,實(shí)例化對(duì)應(yīng)的產(chǎn)品類進(jìn)行生產(chǎn)】
//對(duì)應(yīng)的實(shí)現(xiàn)其實(shí)就是一個(gè)switch或者php8函數(shù)新出的match函數(shù)
//下面用最新的match函數(shù)做演示
class CalculateFactory{
    public static function setCalculate( $type = null ){
        return match( $type ){
            'add' => (function(){
                return new CalculateAdd();
            })(),
            'sub' => (function(){
                return new CalculateSub();
            })(),
            default => null;
        };
    }
}
//具體使用
$calculate = CalculateFactory::setCalculate('add');
$calculate->setNumberA = 1;
$calculate->setNumberB = 2;
//計(jì)算
echo $calculate->getResult;//echo 3

總結(jié):

簡(jiǎn)單工廠模式其實(shí)就是創(chuàng)建一個(gè)基類【abstract】,該類存放所有具體生產(chǎn)產(chǎn)品類的共用的代碼,但是沒有執(zhí)行過程,然后具體生產(chǎn)產(chǎn)品的類全部繼承基類再實(shí)現(xiàn)各自的生產(chǎn)過程。最后創(chuàng)建一個(gè)工廠類,該類用來根據(jù)傳入的參數(shù)來獲取所需的生產(chǎn)類

工廠方法模式 又稱為工廠模式,屬于創(chuàng)造型模式。在工廠模式中,工廠類的父類只負(fù)責(zé)定義公共接口,并不執(zhí)行實(shí)際的生產(chǎn)動(dòng)作。實(shí)際的生產(chǎn)動(dòng)作則交給工廠的子類來完成。這樣做將類的的實(shí)例化延遲到了工廠的子類,通過工廠的子類來完成實(shí)例化具體的產(chǎn)品,也就是生產(chǎn)

在工廠模式中,跟簡(jiǎn)單工廠模式不一樣的是,有一個(gè)抽象的工廠類【即interface CalculateFactory】,可以是接口/抽象類,這個(gè)抽象的工廠類可以派生出多個(gè)具體的工廠類【即FactoryAdd以及FactorySub】

代碼實(shí)現(xiàn)【以下代碼需要用到上面的生產(chǎn)抽象類】

以下代碼需要用到上面的生產(chǎn)抽象類:abstract class Calculate

以及具體的生產(chǎn)類,即:CalculateAdd 以及 CalculateSub。下面不再重復(fù)實(shí)現(xiàn)

interface CalculateFactory{
    public function CreateCalculate();
}
class FactoryAdd implements CalculateFactory{
    public function CreateCalculate(){
        return new CalculateAdd();
    }
}
class FactorySub implements CalculateFactory{
    public function CreateCalculate(){
        return new CalculateSub();
    }
}
//具體使用
//創(chuàng)建工廠實(shí)例
$calculateFactory = new FactoryAdd();
$add = $calculateFactory->CreateCalculate();
$add->setNumberA( 1 );
$add->setNumberB( 2 );
//計(jì)算
echo $add->getResult();//echo 3

總結(jié):

工廠模式相比于簡(jiǎn)單工廠模式的區(qū)別在于,在簡(jiǎn)單工廠模式中,只有一個(gè)工廠來生產(chǎn)對(duì)應(yīng)的生產(chǎn)對(duì)象【即CalculateFactory】。而在工廠模式中,每一個(gè)生產(chǎn)產(chǎn)對(duì)象都由自己的工廠來生產(chǎn),并且這些工廠都繼承自同一個(gè)接口【即 interface CalculateFactory】

抽象工廠模式 抽象工廠模式提供創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口,而且無需指定它們具體的類。這么理解很抽象。通俗一點(diǎn)的解釋就是,相比于上面的工廠模式來講,抽象工廠模式在每個(gè)不同的工廠之上又有一個(gè)超級(jí)工廠,這個(gè)超級(jí)工廠是抽象的接口【interface】,用來生產(chǎn)具體的工廠

在抽象工廠模式中,有多個(gè)抽象的產(chǎn)品類【即abstract class Phone以及abstract class Android】,可以是接口/抽象類/普通類,每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類【即class IPhone / class MiPhone 以及 class IOS / class Android】。一個(gè)抽象的工廠類【即interface AbstractFactory】可以派生出多個(gè)具體的工廠類【即class iPhoneFactory以及class MiFactory】,且每個(gè)具體的工廠類可以創(chuàng)建多個(gè)產(chǎn)品類的實(shí)例【即都有createPhone和createSystem】

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

//抽象的產(chǎn)品類
abstract class Phone{}
abstract class System{}
//具體的產(chǎn)品類
class IPhone extends Phone{}
class MiPhone extends Phone{}
//具體的產(chǎn)品類
class IOS extends System{}
class Android extends System{}
//超級(jí)工廠
interface AbstractFactory{
    public function createPhone();
    public function createSystem();
}
//具體的蘋果工廠
class iPhoneFactory implements AbstractFactory{
    //生產(chǎn)蘋果手機(jī)
    public function createPhone(){
        return new IPhone();
    }
    //生產(chǎn)蘋果系統(tǒng)
    public function createSystem(){
        return new IOS();
    }
}
//具體的小米工廠
class MiFactory implements AbstractFactory{
    //生產(chǎn)小米手機(jī)
    public function createPhone(){
        return new MiPhone();
    }
    //生產(chǎn)安卓系統(tǒng)
    public function createSystem(){
        return new Android();
    }
}

總結(jié):

抽象工廠模式相比于工廠模式,抽象工廠模式提供了一個(gè)接口用來規(guī)定所需要生產(chǎn)的產(chǎn)品。每個(gè)繼承于該接口的工廠都能按照指定的模式進(jìn)行生產(chǎn)【代碼中的AbstarctFactory】

以上三種工廠模式,最終都是為了將重復(fù)的代碼提取出來,并且按照特定的需求場(chǎng)景歸納好,進(jìn)行解耦和復(fù)用,以便在需要的場(chǎng)景中直接使用

三種模式的概括為:

簡(jiǎn)單工廠:

一個(gè)抽象產(chǎn)品類(可以是:接口,抽象類,普通類),可以派生出多個(gè)具體產(chǎn)品類

單獨(dú)一個(gè)具體的工廠類

每個(gè)具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例

工廠模式:

一個(gè)抽象產(chǎn)品類(可以是:接口,抽象類,普通類),可以派生出多個(gè)具體產(chǎn)品類

一個(gè)抽象工廠類(可以是:接口,抽象類),可以派生出多個(gè)具體工廠類

每個(gè)具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例

抽象工廠:

多個(gè)抽象產(chǎn)品類(可以是:接口,抽象類,普通類),每個(gè)抽象產(chǎn)品類可以派生出多個(gè)具體產(chǎn)品類

一個(gè)抽象工廠類(可以是:接口,抽象類),可以派生出多個(gè)具體工廠類

每個(gè)具體工廠類可以創(chuàng)建多個(gè)具體產(chǎn)品類的實(shí)例

三個(gè)模式之間的區(qū)別:

簡(jiǎn)單工廠模式只有一個(gè)抽象產(chǎn)品類,只有一個(gè)具體的工廠類

工廠方法模式只有一個(gè)抽象產(chǎn)品類,而抽象工廠模式有多個(gè)抽象產(chǎn)品類

工廠方法模式的具體工廠類只能創(chuàng)建一個(gè)具體產(chǎn)品類的實(shí)例,而抽象工廠模式可以創(chuàng)建多個(gè)具體產(chǎn)品類的實(shí)例

工廠模式與反射的結(jié)合使用

可以利用反射的特性來實(shí)現(xiàn)工廠模式的生產(chǎn)過程,結(jié)合Laravel-admin進(jìn)行舉例

先看下以下的代碼,需求背景:需要根據(jù)角色不同顯示不同的權(quán)限按鈕

inRoles([AdminUserModel::getAssignmentRole()])) {
                $grid->disableBatchActions();
                $grid->disableEditButton();
                $grid->disableCreateButton();
                $grid->disableDeleteButton();
            } elseif (Admin::user()->inRoles([AdminUserModel::getEvaluatorRole()])) {
                $grid->disableBatchActions();
                $grid->disableEditButton();
                $grid->disableCreateButton();
                $grid->disableDeleteButton();
                $grid->actions(function (Grid\Displayers\Actions $actions) {
                    $actions->append(new ConfirmCloseTaskAction());
                });
            } else {
                $grid->disableCreateButton();
                $grid->disableDeleteButton();
                $grid->disableEditButton();
                $grid->disableBatchActions();
                $grid->disableViewButton();
                $grid->disableActions();
            }
    }
}

以上的代碼很明顯一看就顯得很臃腫。且隨著業(yè)務(wù)的增加【即Controller的增加】以及角色的增加,需要寫更多重復(fù)的判斷以及重復(fù)的代碼

解決思路:

不同的角色需要擁有的不同的權(quán)限,每個(gè)角色都可以用一個(gè)固定的方法來設(shè)置權(quán)限,這個(gè)固定的方法可以為不同的角色設(shè)置權(quán)限。這些條件剛好滿足工廠模式的使用場(chǎng)景:即:

抽象出一個(gè)產(chǎn)品類來派生出多個(gè)角色的權(quán)限產(chǎn)品類

抽象出一個(gè)工廠類來派生出多個(gè)具體的工廠類,這些工廠類表現(xiàn)為對(duì)應(yīng)要使用權(quán)限按鈕的場(chǎng)景

每個(gè)具體工廠【使用權(quán)限按鈕的場(chǎng)景】可以創(chuàng)建多個(gè)具體產(chǎn)品類【即實(shí)例化多個(gè)角色的權(quán)限產(chǎn)品】

代碼如下【在下面的代碼中,將使用反射來代替工廠的生產(chǎn)】

1) 抽象出一個(gè)產(chǎn)品類來派生出多個(gè)角色的權(quán)限產(chǎn)品類


2,3) 2,3兩個(gè)步驟包含在一起。抽象出一個(gè)工廠類來派生出多個(gè)具體的工廠類,這些工廠類表現(xiàn)為對(duì)應(yīng)要使用權(quán)限按鈕的場(chǎng)景。其中,setRoleAction方法使用反射來直接生產(chǎn),也就是替代了每個(gè)具體工廠類創(chuàng)建實(shí)例的過程

inRoles([$role]);
    }
    /**
     * 調(diào)用對(duì)應(yīng)的方法
     * [該方法其實(shí)就是工廠模式中的工廠,專門來生產(chǎn)的]
     * [多個(gè)工廠對(duì)應(yīng)的就是各個(gè)需要用到Action權(quán)限的Controller控制器]
     * [每個(gè)Controller控制器來生產(chǎn)自己的Action權(quán)限]
     * [這個(gè)生產(chǎn)是通過反射來實(shí)現(xiàn)]
     *
     * @param Grid $grid
     * @param string $role
     * @param string $class
     * @throws \ReflectionException
     */
    protected static function setRoleAction(Grid $grid, string $role, string $class)
    {
        $r = new \ReflectionClass($class);
        $methodName = $role . 'Action';
        if (!$r->hasMethod($methodName))
            throw new \Exception('Method Not Found [ method : ' . $methodName . ' ] ');
        $method = $r->getMethod($methodName);
        $method->invoke($r->newInstance(), $grid);
    }
}

根據(jù)以上的反射來實(shí)現(xiàn)實(shí)例化的過程,上面的TaskController的權(quán)限可以簡(jiǎn)化成下面的代碼:

showActions();
        $grid->showViewButton();
    }
    //在TaskController下有需要使用權(quán)限按鈕的角色
    //財(cái)務(wù)角色
    public function financeAction(Grid $grid)
    {
        $grid->showActions();
        $grid->showViewButton();
    }
    //在TaskController下有需要使用權(quán)限按鈕的角色
    //業(yè)務(wù)員角色
    public function salesmanAction(Grid $grid)
    {
    }
    //....其他角色
}

經(jīng)過使用設(shè)計(jì)模式封裝后,上面TaskController中控制權(quán)限的代碼直接優(yōu)化成如下:【優(yōu)雅了不少~】

inRoles([AdminUserModel::getAssignmentRole()])) {
                $grid->disableBatchActions();
                $grid->disableEditButton();
                $grid->disableCreateButton();
                $grid->disableDeleteButton();
            } elseif (Admin::user()->inRoles([AdminUserModel::getEvaluatorRole()])) {
                $grid->disableBatchActions();
                $grid->disableEditButton();
                $grid->disableCreateButton();
                $grid->disableDeleteButton();
                $grid->actions(function (Grid\Displayers\Actions $actions) {
                    $actions->append(new ConfirmCloseTaskAction());
                });
            } else {
                $grid->disableCreateButton();
                $grid->disableDeleteButton();
                $grid->disableEditButton();
                $grid->disableBatchActions();
                $grid->disableViewButton();
                $grid->disableActions();
            }
            */
    }
}

總結(jié):

設(shè)計(jì)模式以及反射通常在寫框架的時(shí)候用的比較多。但是在項(xiàng)目中,適當(dāng)?shù)氖褂迷O(shè)計(jì)模式以及反射,能夠讓代碼更加健壯以及可擴(kuò)展,也很優(yōu)雅~


標(biāo)題名稱:PHP高級(jí)特性:反射與工廠設(shè)計(jì)模式如何結(jié)合使用
文章源于:http://www.5511xx.com/article/dpoogds.html