[譯]Magento中的12種設(shè)計(jì)模式

20170331149095046779669.png

原文地址:
http://magenticians.com/12-design-patterns-magento

Magento中的架構(gòu)通常被認(rèn)為是過度設(shè)計(jì)了栗涂。如果從架構(gòu)的角度去看Magento的代碼,很容易發(fā)現(xiàn)它至少使用了下面介紹的的十二種設(shè)計(jì)模式祈争。

Magento its architecture is sometimes deemed overly engineered. If we look at it from a helicopter view, commonly used design patterns are easily spotted. Here are 12 of them.

介紹

給出一個(gè)需求斤程,解決的方案有很多,設(shè)計(jì)模式便是其中的最佳方法,可以解決特定環(huán)境下的同類問題忿墅。設(shè)計(jì)模式的代碼是可重復(fù)利用的扁藕,對于提高工作效率大有裨益,那從長遠(yuǎn)角度考慮疚脐,是不是應(yīng)當(dāng)在代碼中盡可能多的使用設(shè)計(jì)模式呢亿柑?明顯不是,一名優(yōu)秀的軟件開發(fā)者知道何時(shí)使用設(shè)計(jì)模式棍弄,并不會無的放矢望薄。早期Magento框架中的比較出色的一點(diǎn)是,其中的絕大部分(甚至所有)使用的設(shè)計(jì)模式的方式都有其用意所在(畫外音:說明Magento的開發(fā)者是一名優(yōu)秀的軟件開發(fā)者呼畸,不然本文也就沒有意義了)痕支。

本文是根據(jù)@Ryan Street的系列博文整理而得的。

Introduction

A software design pattern is a reusable solution to an often occurring problem. This doesn’t mean that software is better if it has more design patterns. Instead, a good software engineer should be able to spot the problem and implement the pattern instead of introducing implementations without purpose. The earlier behavior is leadingly noticeable in Magento, where most if not all design pattern-implementations have a purpose.
This is a compilation of an article-series which originally appeared on Ryan Street’s blog (@ryanstreet).

模式1:MVC

簡易程度:??
使用場景:?????

Model-View-Controller,即模型-視圖-控制器,簡稱MVC蛮原,應(yīng)該是最廣為人知的一種設(shè)計(jì)模式(大多數(shù)使用者甚至都不會將它視為設(shè)計(jì)模式)卧须。

這是一種將業(yè)務(wù)邏輯、頁面展示瞬痘、邏輯分離開來的設(shè)計(jì)模式故慈。Mageno中使用了大量的xml文件作為邏輯模板,使用pthml(混合了HTML和PHP)文件作為它的視圖框全,剩下的模型依賴Varien的ORM察绷。大多數(shù)的業(yè)務(wù)邏輯發(fā)生在模型中,而控制器將模型數(shù)據(jù)映射到視圖津辩,Magento的視圖包含了太多的邏輯而顯示很笨重拆撼,不得不通過一個(gè)專門的php類(Block類)進(jìn)行渲染。

Model View Controller Pattern

Model View Controller, MVC for short, is a design pattern where business, presentation and coupling logic are separated. Magento heavily utilizes XML as templating-logic and HTML mixed with PHP files for its views. Models are backed by ORM. Most business logic happens in the models whereas the controllers map the model-data to the views.
Because Magento its views are “fat” – they often contain a lot of logic – its not rare that views have an additional PHP class (the Block system) which will help with rendering

模式2: 前端控制器模式

簡易程度:??
使用場景:?????

前端控制器模式確保有且只有一個(gè)入口喘沿。所有的請求都會先從前端控制器那里走一遭闸度,被識別后路由分發(fā)到指定的controller,進(jìn)行特定的處理蚜印。
在Magento唯一一個(gè)入口文件index.php就起到了前端控制器的作用莺禁,它通過Mage::app()方法實(shí)現(xiàn)應(yīng)用環(huán)境的初始化并將請求路由到正確的controller中。

Front Controller Pattern

The front controller pattern makes sure that there is one and only one point of entry. All requests are investigated, routed to the designated controller and then processed accordingly to the specification. The front controller is responsible of initializing the environment and routing requests to designated controllers.
Magento has only one point of entry (index.php) which will initialize the application environment (Mage::app()) and route the request to the correct controller.

模式3:工廠模式

簡易程度:???
使用場景:?????
工廠模式的“工廠”二字已經(jīng)充分表露了它的功能————如工廠的流水線一般統(tǒng)一進(jìn)行類的實(shí)例化窄赋。

它被廣泛應(yīng)用在Magento的代碼庫中哟冬,負(fù)責(zé)自動加載系統(tǒng)。在config.xml文件中定義一個(gè)module的別名后忆绰,工廠就悄咪咪的記錄了別名對應(yīng)的類及類所在的位置浩峡。

Mage核心類中有很多輔助實(shí)現(xiàn)工廠的方法,其中的Mage::getModel()方法可以接收一個(gè)類的別名返回類的實(shí)例错敢,如Mage::getModel('catalog/product')返回產(chǎn)品類Mage_Catalog_Model_Product的實(shí)例翰灾。

區(qū)別于傳統(tǒng)的在代碼中直接引入類所在文件并調(diào)用類,工廠模式以統(tǒng)一的方式對類進(jìn)行初始化。

Factory Pattern

As implied by the name, the factory pattern is responsible of factorizing (instantiating) classes. It’s widely used through the Magento code base and leverages the autoloading system in Magento. By defining an alias in a module its config.xml you are letting the factory know where it can find classes.
There are various factory-helper methods in the Mage core class and one of them is getModel(). It accepts an alias for a class and will then return an instance of it. Instead of having include calls scattered through the code base, the factory pattern will instantiate classes in an uniform way.

模式4:單例模式

簡易程度:???
使用場景:?????

另一種獲取類的實(shí)例的方法是Mage::getSingleton()纸淮,它跟Mage::getModel()方法一樣接收一個(gè)類的別名平斩,不同之處在于getSingleton在返回實(shí)例之前,會先去注冊表里瞄一眼咽块,看看這個(gè)類是否已經(jīng)實(shí)例化過了双戳,如果實(shí)例化過了,那這個(gè)實(shí)例就可以被共享了糜芳。

例如飒货,Magento中的session對象,(如customer session或checkout session),被儲存在注冊表中峭竣,可以在代碼不同地方重復(fù)使用塘辅,而不要每次都重新創(chuàng)建

Singleton Pattern

Another way to retrieve an instance of a class, is to call Mage::getSingleton(). It accepts a class alias and before returning an instance, it checks the internal registry whether this class has already been instantiated before – this results in a shared instance. An example of where this is mandatory, is the session storage which should be shared through the code base instead of creating it anew every time.

模式5:注冊模式

簡易程度:???
使用場景:????
(進(jìn)程級別的)

所有的單例都存儲在內(nèi)部注冊表中,這是全局的存儲數(shù)據(jù)的地方,而且不僅限于內(nèi)部使用。下面列舉的注冊相關(guān)的方法可以分別實(shí)現(xiàn)從注冊表中存儲皆撩,查詢扣墩,刪除數(shù)據(jù)。

Mage::register($key,$value)     //存儲
Mage::registry()    //查詢
Mage::unregister()  //刪除

這種注冊表的方法通常應(yīng)用于數(shù)據(jù)不能傳遞時(shí)的場景下扛吞,進(jìn)行數(shù)據(jù)的傳輸呻惕。并且數(shù)據(jù)格式是key-value的格式

比如訂單生成的時(shí)候register一個(gè)key,然后在sales_order_save_after事件的observer方法中通過registry讀取之前register的key

Registry Pattern

All the singletons are stored in the internal registry: a global scoped Container for storing data. It is not only for internal use. The Mage::register($key, $value),::registry($key) and ::unregister($key) methods can be respectively used for storing, retrieving and removing data from the registry. The registry is often used for transferring data between scopes when they cannot be passed on, otherwise.

模式6:原型模式

簡易程度:????
使用場景:???

原型模式是對工廠模式功能的補(bǔ)充,它定義類的實(shí)例可以根據(jù)其父類(原型)檢索其它類的實(shí)例滥比。

舉個(gè)栗子亚脆,Mage_Catalog_Model_Product類有一個(gè)getTypeInstance方法來獲取特定的類Mage_Catalog_Model_Product_Type的對象,后者包含了不適用于其它產(chǎn)品的一系列的方法和屬性盲泛。
Mage_Downloadable_Model_Product_Type這個(gè)Downloadable產(chǎn)品的類又最終繼承了Mage_Catalog_Model_Product_Type類濒持。如果您正在下單并想要調(diào)用Downloadable類型產(chǎn)品的特定方法,則需要首先使用原始的產(chǎn)品類的getTypeInstance方法對其進(jìn)行實(shí)例化寺滚。

Prototype Pattern

Where the factory pattern (#3 on our list) stops, is where the prototype pattern continues. It defines that instances of classes can retrieve a specific other class instance depending on its parent class (the prototype). A notable example is the Mage_Catalog_Model_Product class which has a getTypeInstance method to retrieve the specificMage_Catalog_Model_Product_Type with a specific subset of methods and properties not applicable to all products.
For example, the Mage_Downloadable_Model_Product_Type ultimately extends the Mage_Catalog_Model_Product_Type. If you are iterating over an order and want to call a specific method of a downloadable product, you will need to factorize it first with the getTypeInstance method of the original product.

模式7:對象池模式

簡易程度:???
使用場景:???
對象池模式只是一個(gè)包含對象的集合柑营,防止它們一次又一次被分配和銷毀。

在Magento中村视,對象池模式并不常見官套,只會在處理嚴(yán)重影響服務(wù)器性能的重任務(wù)時(shí)被使用,例如批量導(dǎo)入產(chǎn)品的時(shí)候蚁孔。

可以使用Mage::objects()方法訪問對象池(由Varien_Object_Cache類管理)

Object Pool Pattern

The object pool pattern is simply a box with objects so that they do not have to be allocated and destroyed over and over again. It’s not used a lot in Magento other than for heavy tasks where resources can get limited soon, like importing products. The object pool (managed by Varien_Object_Cache) can be accessed with Mage::objects().

模式8 迭代器模式

簡易程度:????
使用場景:??
迭代器模式定義了一個(gè)公共方法來遍歷具有對象的結(jié)合奶赔。

在Magento中,這是由Varien_Data_Collection類實(shí)現(xiàn)的勒虾,它依次使用各種baked-in的PHP類(如ArrayIterator)來為數(shù)組提供更多的OO接口纺阔。這樣可以確保模型集合始終具有一個(gè)通用的API來遍歷瘸彤,而不依賴于實(shí)際的模型修然。

Iterator Pattern

The iterator pattern defines that there is a shared way to iterate over a container with objects. In Magento, this is handled by the Varien_Data_Collection which on its turn uses various baked-in PHP classes (like ArrayIterator) for having a more OO-interface to arrays. This ensures that model-collections will always have a common API to iterate over without being dependent of the actual models.

模式9:延遲加載模式

簡易程度:??
使用場景:????

延遲加載確保加載數(shù)據(jù)被延遲到實(shí)際需要的時(shí)間點(diǎn),這導(dǎo)致更少的資源利用。 Magento的延遲加載行為之一就是collection集合。如果使用Mage::getModel('catalog/product')->getCollection()獲取產(chǎn)品collection時(shí)愕宋,并沒有操作數(shù)據(jù)庫玻靡。只有當(dāng)load之后,遍歷collection中的product對象或者查詢collection的數(shù)量時(shí)中贝,才會對數(shù)據(jù)庫進(jìn)行讀寫操作囤捻。

Lazy Loading Pattern

Lazy loading ensures that loading data is delayed until the point when it is actually needed. This results in less resources being used. One of the lazy loading behaviors of Magento is that of collections. If you were to retrieve a collection of products with Mage::getModel('catalog/product')->getCollection(), the database will only be touched when you actually access the collection by, for example, iterating over it or retrieving the count of models found.

模式10:服務(wù)定位器模式

簡易程度:????
使用場景:???

服務(wù)定位器模式抽取某個(gè)服務(wù)的檢索。它遵守其抽象基礎(chǔ)邻寿,可以在不破壞任何東西的情況下改變服務(wù)蝎土,而且可以看到適合其目的的服務(wù)。
例如绣否,Ryan的數(shù)據(jù)庫連接誊涯。

另一個(gè)例子是Magento的緩存機(jī)制,通過Mage::getCache()存儲緩存蒜撮,Mage::getCache()是由Zend或其他供應(yīng)商提供的緩存存儲的代理服務(wù)定位器暴构。

再如,隊(duì)列的實(shí)現(xiàn)

Service Locator Pattern

The service locator pattern abstracts away the retrieval of a certain service. This allows for changing the service without breaking anything (as it adheres to its abstract foundation) but also fetching the service as seen fit for its purpose.
Ryan exemplifies this with database connections. Another example is that of Magento its caching mechanism where Mage::getCache() is a service locator by-proxy for the cache storage supplied by Zend or other vendors.

模式11:模塊模式

簡易程度:???
使用場景:????

任何熟悉Magento開發(fā)的人都會很自然的接觸模塊模式段磨。它基本上定義了不同的功能被分組成獨(dú)立的模塊取逾,它們彼此獨(dú)立,并且可以根據(jù)需要插入到Magento主系統(tǒng)中苹支。在理想情況下砾隅,模塊模式的實(shí)現(xiàn)將確保每個(gè)元素都可以被刪除或交換。 PHP中模塊模式的主角之一是Composer軟件包管理器债蜜。
雖然Magento嚴(yán)重依賴于模塊化架構(gòu)琉用,但它并不是模塊化的。某些功能與核心密切相關(guān)策幼,不能輕易改變邑时。還大量使用超全局的Mage核心類,引入了各種不受監(jiān)管的系統(tǒng)級依賴關(guān)系特姐。

Module Pattern

Anyone familiar with Magento development has stumbled upon the module pattern. It basically defines that different domains are grouped into separate modules which function independent of each other and can be plugged-in to the main system as deemed appropriate. In an ideal situation, an implementation of the module pattern would make sure that each element can be removed or swapped. One of the protagonists of the module pattern in PHP is the Composer package manager.
Though Magento heavily relies on a modular architecture, its not modular to the bone. Certain functionality is heavily tied to the core and can not be easily changed. There is also the heavy usage of the super-global Mage core-class which introduces all sorts of system-wide dependencies not easily overseen.

模式12:觀察者模式

簡易程度:??
使用場景:?????

Magento的事件驅(qū)動架構(gòu)是實(shí)現(xiàn)觀察者模式的結(jié)果晶丘。通過定義觀察者(或監(jiān)聽者),可以掛接額外的代碼唐含,隨著觀察到的事件觸發(fā)浅浮,這些代碼將被調(diào)用。

Magento使用config.xml存儲并定義觀察者捷枯。使用Mage::dispatchEvent($eventName滚秩,$data)觸發(fā)事件,eventName是事件名淮捆,data是參數(shù)郁油。事件觸發(fā)后會將查詢數(shù)據(jù)存儲本股,并觸發(fā)相應(yīng)的$event觀察者。
除了使用模塊之外桐腌,還可以使用事件來定制現(xiàn)有的邏輯拄显,而不用接觸現(xiàn)有的代碼。

舉個(gè)栗子案站,下單完成后發(fā)送郵件通知用戶躬审,不需要將寫郵件的代碼跟下單的代碼寫在一起,只要下單完成后觸發(fā)事件sales_order_save_after,在config.xml中定義sales_order_save_after事件的觀察者蟆盐,然后在觀察者方法中寫相應(yīng)的發(fā)送郵件的代碼

Observer Pattern

Magento its event-driven architecture is a result of an implementation of the observer pattern. By defining observers (or listeners), extra code can be hooked which will be called upon as the observed event fires. Magento uses its XML-data storage to define observers. If an event is fired with Mage::dispatchEvent($eventName, $data), the data storage will be consulted and the appropriate observers for $event will be fired.
In addition to using modules, events can be used to customize existing logic without touching the existing code.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末承边,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子石挂,更是在濱河造成了極大的恐慌炒刁,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件誊稚,死亡現(xiàn)場離奇詭異翔始,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)里伯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門城瞎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人疾瓮,你說我怎么就攤上這事脖镀。” “怎么了狼电?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵蜒灰,是天一觀的道長。 經(jīng)常有香客問我肩碟,道長强窖,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任削祈,我火速辦了婚禮翅溺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘髓抑。我一直安慰自己咙崎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布吨拍。 她就那樣靜靜地躺著褪猛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪羹饰。 梳的紋絲不亂的頭發(fā)上伊滋,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天碳却,我揣著相機(jī)與錄音,去河邊找鬼新啼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛刹碾,可吹牛的內(nèi)容都是我干的燥撞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼迷帜,長吁一口氣:“原來是場噩夢啊……” “哼物舒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起戏锹,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤冠胯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后锦针,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荠察,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年奈搜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了悉盆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡馋吗,死狀恐怖焕盟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情宏粤,我是刑警寧澤脚翘,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站绍哎,受9級特大地震影響来农,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜崇堰,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一备图、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧赶袄,春花似錦揽涮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至敬辣,卻和暖如春雪标,著一層夾襖步出監(jiān)牢的瞬間零院,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工村刨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留告抄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓嵌牺,卻偏偏與公主長得像打洼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子逆粹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • **2014真題Directions:Read the following text. Choose the be...
    又是夜半驚坐起閱讀 9,389評論 0 23
  • 03 A2:見面募疮,s床。后來她打電話約我見面僻弹,我把第一次見面的地點(diǎn)框架到我家里阿浓。在沒見面以前她就對我很有感覺了,見...
    一條老白狼閱讀 448評論 0 0
  • 在昨天晚7點(diǎn)之前稿蹲,我有一個(gè)愉快的周末,窩在家里追劇吃零食鹊奖,等老爸回來做了兩菜一湯苛聘,兩人還喝了點(diǎn)小酒,簡直不能太...
    松樓閱讀 622評論 0 1
  • 中午在宿舍人熱的實(shí)在受不了网梢,索性背著包來到校園里,尋到一處僻靜處赂毯,在石凳上放了紙战虏,靜靜地坐著,享受著33度下的涼風(fēng)...
    Hebetow閱讀 995評論 2 6
  • 昨夜夢中党涕,刀光劍影烦感。漫走黃沙驚醒,疑是圍城膛堤。 今朝月下手趣,風(fēng)走人停。呼嘯寒霜清景肥荔,沖破圍城绿渣。
    蟬鳴夏閱讀 282評論 3 5