摘要:反射提供給面向?qū)ο缶幊炭梢宰允〉哪芰Γ捶瓷洹T诤唵喂S模式中,根據(jù)傳遞的參數(shù)來返回不同的類的實例簡單工廠模式又稱為靜態(tài)工廠方法模式。也就是簡單工廠模式工廠工廠類。
利用反射來實現(xiàn)工廠模式的生產(chǎn)而無需創(chuàng)建特定的工廠類
轉(zhuǎn)載請注明來源
[Relfection]
Reflection
PHP
提供了完整的反射 API
,提供了內(nèi)省類、接口、函數(shù)、方法和擴(kuò)展的能力。此外,反射 API
提供了方法來取出函數(shù)、類和方法中的文檔注釋。詳細(xì)見PHP官網(wǎng)
PHP反射簡介 Reflection
能干什么[protected/private]
,這些特性使得PHP的使用靈活性得到非常大的提高。例如:Laravel
框架的所謂優(yōu)雅所在,即容器、依賴注入、IOC
控制反轉(zhuǎn)就是依靠這些特性實現(xiàn)的Hyperf
框架的注解路由也是根據(jù)反射獲得注釋來實現(xiàn)的生成文檔
因為反射可以獲取類屬性和方法的訪問權(quán)限,可以掃描整個項目的所有文件再使用反射來生成文檔測試驅(qū)動開發(fā)
利用反射獲取該類的所有方法的特性,進(jìn)行測試驅(qū)動開發(fā)開發(fā)插件
利用反射獲取類的內(nèi)部結(jié)構(gòu)的特性,實現(xiàn) Hook
功能,例如框架插件的實現(xiàn)Reflection
的優(yōu)缺點優(yōu)點
反射提供了對類的反解析,從而相比原本面向?qū)ο蟮木幊谭绞将@得了極高的靈活性,以及合理的使用能夠讓代碼看起來更加優(yōu)雅以及簡潔。原本在面向?qū)ο蟮木幊谭绞街校褂靡粋€類的實例需要先 new
出一個對象再使用方法,但是使用了反射機(jī)制,只需要提供一個該類的方法然后使用反射機(jī)制即可使用該對象或者方法。Laravel
框架正是使用了大量的反射才獲得了優(yōu)雅的美譽,Swoole
的 Hyperf
框架的注解路由的實現(xiàn)也是使用了反射缺點
同時,由于反射是類實例化的反過程,破壞了面向?qū)ο蟮姆庋b性,直接將類的整個內(nèi)部結(jié)構(gòu)暴露,這就導(dǎo)致了反射一旦濫用,代碼將難于管理,整個項目將非常混亂,甚至導(dǎo)致業(yè)務(wù)執(zhí)行錯亂。尤其在大項目幾十人的團(tuán)隊中,試想一下,原本的面向?qū)ο螅桓嬖V什么可以用,什么不可以用,CTO寫好了底層代碼,其他人繼承后然后使用就行,內(nèi)部結(jié)構(gòu)啥的其他人都不知道。一旦用上了反射,如果有一個程序員不小心將原本是 protected
或者是 private
的屬性或者方法設(shè)置成了可以訪問,其他程序員在不知情的情況調(diào)用了本該隱藏的數(shù)據(jù)或者方法,那將導(dǎo)致不可預(yù)測的災(zāi)難【見下面示例代碼】IDE
中通過直接直接點擊代碼溯源,對于新手真的是很蛋疼,Laravel
和Hyperf
都是如此private
方法設(shè)置成外部可訪問#Example:setAccessible(true);echo $method->invoke(new Foo);// echos "7"?>
[簡單工廠模式] [工廠模式] [抽象工廠模式]
簡單工廠模式
又稱為靜態(tài)工廠方法模式。簡單的說,就是創(chuàng)建對象的方式是通過一個靜態(tài)方法來實現(xiàn)的。在簡單工廠模式中,根據(jù)傳遞的參數(shù)來返回不同的類的實例PHP
中在簡單工廠模式中,有一個抽象的產(chǎn)品類【即abstract class Calculate
】,這個抽象類可以是接口/抽象類/普通類
。這個抽象的產(chǎn)品類可以派生出多個具體的產(chǎn)品類【即class CalculateAdd
以及class CalculateSub
】。最后再由一個具體的工廠類【即class CalculateFactory
】來獲取所需要的產(chǎ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; } //獲取計算結(jié)果【獲取生產(chǎn)出的產(chǎn)品】 public function getResult(){ return null; }}
//加法運算class CalculateAdd extends Calculate{ //獲取運算結(jié)果【獲取具體的產(chǎn)品】 public function getResult(){ return $this->number_a + $this->number_b; }}//減法運算class CalculateSub extends Calculate{ //獲取運算結(jié)果【獲取具體的產(chǎn)品】 public function getResult(){ return $this->number_a - $this->number_b; }}//乘法 / 除法 等等其他運算【其他產(chǎn)品】
簡單工廠模式
php
中,實現(xiàn)的方式其實就一個 switch
函數(shù)或者是 php8
新出的 match
函數(shù)來實例化所需要的產(chǎn)品生產(chǎn)類//根據(jù)運算不同實例化不同的對象//【也就是根據(jù)所需產(chǎn)品,實例化對應(yīng)的產(chǎn)品類進(jìn)行生產(chǎn)】//對應(yīng)的實現(xiàn)其實就是一個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;//計算echo $calculate->getResult;//echo 3
總結(jié)
:簡單工廠模式其實就是創(chuàng)建一個基類【abstract
】,該類存放所有具體生產(chǎn)產(chǎn)品類的共用的代碼
,但是沒有執(zhí)行過程
,然后具體生產(chǎn)產(chǎn)品的類全部繼承基類再實現(xiàn)各自的生產(chǎn)過程
。最后創(chuàng)建一個工廠類,該類用來根據(jù)傳入的參數(shù)
來獲取所需的生產(chǎn)類
工廠方法模式
又稱為工廠模式,屬于創(chuàng)造型模式。在工廠模式中,工廠類的父類只負(fù)責(zé)定義公共接口,并不執(zhí)行實際的生產(chǎn)動作。實際的生產(chǎn)動作則交給工廠的子類來完成。這樣做將類的的實例化延遲到了工廠的子類,通過工廠的子類來完成實例化具體的產(chǎn)品,也就是生產(chǎn)interface CalculateFactory
】,可以是接口/抽象類
,這個抽象的工廠類可以派生出多個具體的工廠類【即FactoryAdd
以及FactorySub
】以下代碼需要用到上面的生產(chǎn)抽象類:abstract class Calculate
以及具體的生產(chǎn)類,即:CalculateAdd
以及 CalculateSub
。下面不再重復(fù)實現(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)建工廠實例$calculateFactory = new FactoryAdd();$add = $calculateFactory->CreateCalculate();$add->setNumberA( 1 );$add->setNumberB( 2 );//計算echo $add->getResult();//echo 3
只有一個工廠
來生產(chǎn)對應(yīng)的生產(chǎn)對象【即CalculateFactory
】。而在工廠模式中,每一個生產(chǎn)產(chǎn)對象都由自己的工廠
來生產(chǎn),并且這些工廠都繼承
自同一個接口【即 interface CalculateFactory
】抽象工廠模式
抽象工廠模式提供創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而且無需指定它們具體的類。這么理解很抽象。通俗一點的解釋就是,相比于上面的工廠模式來講,抽象工廠模式在每個不同的工廠之上又有一個超級工廠,這個超級工廠是抽象的接口【interface
】,用來生產(chǎn)具體的工廠abstract class Phone
以及abstract class Android
】,可以是接口/抽象類/普通類
,每個抽象產(chǎn)品類可以派生出多個具體產(chǎn)品類【即class IPhone
/ class MiPhone
以及 class IOS
/ class Android
】。一個抽象的工廠類【即interface AbstractFactory
】可以派生出多個具體的工廠類【即class iPhoneFactory
以及class MiFactory
】,且每個具體的工廠類可以創(chuàng)建多個產(chǎn)品類的實例【即都有createPhone
和createSystem
】//抽象的產(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{}//超級工廠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(); }}
AbstarctFactory
】一個抽象產(chǎn)品類(可以是:接口,抽象類,普通類),可以派生出多個具體產(chǎn)品類
多帶帶一個具體的工廠類
每個具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例
一個抽象產(chǎn)品類(可以是:接口,抽象類,普通類),可以派生出多個具體產(chǎn)品類
一個抽象工廠類(可以是:接口,抽象類),可以派生出多個具體工廠類
每個具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例
多個抽象產(chǎn)品類(可以是:接口,抽象類,普通類),每個抽象產(chǎn)品類可以派生出多個具體產(chǎn)品類
一個抽象工廠類(可以是:接口,抽象類),可以派生出多個具體工廠類
每個具體工廠類可以創(chuàng)建多個具體產(chǎn)品類的實例
簡單工廠模式只有一個抽象產(chǎn)品類,只有一個具體的工廠類
工廠方法模式只有一個抽象產(chǎn)品類,而抽象工廠模式有多個抽象產(chǎn)品類
工廠方法模式的具體工廠類只能創(chuàng)建一個具體產(chǎn)品類的實例,而抽象工廠模式可以創(chuàng)建多個具體產(chǎn)品類的實例
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(); } }}
Controller
的增加】以及角色的增加,需要寫更多重復(fù)的判斷以及重復(fù)的代碼抽象出一個產(chǎn)品類來派生出多個角色的權(quán)限產(chǎn)品類
抽象出一個工廠類來派生出多個具體的工廠類,這些工廠類表現(xiàn)為對應(yīng)要使用權(quán)限按鈕的場景
每個具體工廠【使用權(quán)限按鈕的場景】可以創(chuàng)建多個具體產(chǎn)品類【即實例化多個角色的權(quán)限產(chǎn)品】
inRoles([$role]); } /** * 調(diào)用對應(yīng)的方法 * [該方法其實就是工廠模式中的工廠,專門來生產(chǎn)的] * [多個工廠對應(yīng)的就是各個需要用到Action權(quán)限的Controller控制器] * [每個Controller控制器來生產(chǎn)自己的Action權(quán)限] * [這個生產(chǎn)是通過反射來實現(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); }}
showActions(); $grid->showViewButton(); } //在TaskController下有需要使用權(quán)限按鈕的角色 //財務(wù)角色 public function financeAction(Grid $grid) { $grid->showActions(); $grid->showViewButton(); } //在TaskController下有需要使用權(quán)限按鈕的角色 //業(yè)務(wù)員角色 public function salesmanAction(Grid $grid) { } //....其他角色}
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(); } */ }}
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/123756.html
摘要:工廠模式,依賴轉(zhuǎn)移當(dāng)然,實現(xiàn)控制反轉(zhuǎn)的方法有幾種。其實我們稍微改造一下這個類,你就明白,工廠類的真正意義和價值了。雖然如此,工廠模式依舊十分優(yōu)秀,并且適用于絕大多數(shù)情況。 此篇文章轉(zhuǎn)載自laravel-china,chongyi的文章https://laravel-china.org/top...原文地址: http://www.insp.top/learn-lar... ,轉(zhuǎn)載務(wù)必保...
摘要:本文一大半內(nèi)容都是通過舉例來讓讀者去理解什么是控制反轉(zhuǎn)和依賴注入,通過理解這些概念,來更加深入。這種由外部負(fù)責(zé)其依賴需求的行為,我們可以稱其為控制反轉(zhuǎn)。工廠模式,依賴轉(zhuǎn)移當(dāng)然,實現(xiàn)控制反轉(zhuǎn)的方法有幾種。 容器,字面上理解就是裝東西的東西。常見的變量、對象屬性等都可以算是容器。一個容器能夠裝什么,全部取決于你對該容器的定義。當(dāng)然,有這樣一種容器,它存放的不是文本、數(shù)值,而是對象、對象的描...
摘要:使用元數(shù)據(jù)包中包含了中每一個被建模類對應(yīng)的接口。任何對象的元數(shù)據(jù)是使用的實現(xiàn)來表示的。加載模型的序列化形式是個在運行期間獲取元數(shù)據(jù)的有效方法。反射提供一個反射式,可以檢查對象的元數(shù)據(jù)以及一般地訪問和操縱數(shù)據(jù)。 使用元數(shù)據(jù) Java包org.eclipse.emf.ecore中包含了Ecore中每一個被建模類對應(yīng)的接口。任何EMF對象的元數(shù)據(jù)是使用Ecore的實現(xiàn)(implement...
摘要:提供了個常用的預(yù)定義接口,實現(xiàn)某些特定的能力。是啥如官方文檔所述,它提供像訪問數(shù)組一樣訪問對象的能力的接口。它提供了個接口我們實現(xiàn)這個接口,依次對應(yīng)數(shù)組的讀取,設(shè)置,操作。用上了它,可以讓一個類即可以支持對象引用,也支持?jǐn)?shù)組引用。 php提供了6個常用的預(yù)定義接口,實現(xiàn)某些特定的能力。其中最最常用的就是 ArrayAccess 了,像 Laravel 這種流行的框架都用到了它。 Arr...
近期在維護(hù)公司項目的時候遇到一個問題,因為實體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對象賦值的過程中不能夠使用 set 方法,為了實現(xiàn)功能,所以采用了反射的機(jī)制給對象屬性賦值,借此機(jī)會也了解了反射的一些具體用法和使用場景,分以下兩點對反射進(jìn)行分析: 反射的優(yōu)勢和劣勢 反射的應(yīng)用場景 反射的優(yōu)勢和劣勢 ??個人理解,反射機(jī)制實際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...
閱讀 713·2023-04-25 19:43
閱讀 3910·2021-11-30 14:52
閱讀 3784·2021-11-30 14:52
閱讀 3852·2021-11-29 11:00
閱讀 3783·2021-11-29 11:00
閱讀 3869·2021-11-29 11:00
閱讀 3557·2021-11-29 11:00
閱讀 6105·2021-11-29 11:00