2016-11-29 54 views
2

我在openstack中子讀取了下面的代碼。爲什麼在python中使用工廠方法?

class APIRouter(wsgi.Router): 

    @classmethod 
    def factory(cls, global_config, **local_config): 
     return cls(**local_config) 

    def __init__(self, **local_config): 
     # do something. Not using local_config 

我在這裏有兩個問題。

  1. 從工廠代碼我們可以知道它用於創建APIRouter實例。但爲什麼我們需要它?爲什麼我們不僅僅使用api_router = ApiRouter()來獲取實例?

  2. __init__和工廠local_configglobal_config不使用。爲什麼我們在函數中定義它?

我想應該有一些優勢,使用工廠,而不是構造函數。就像JAVA中的設計模式一樣..我希望答案能夠說明優點或原因。更好的一些exapmle

回答

3

這是一個尖銳的問題。我會採取(希望,通知)猜測。我說猜測是因爲當我回顧OpenStack代碼時,它不是我的代碼,也不使用這種特定的配置體系結構。

APIRouter()出現在源代碼中作爲主實例構造函數。 APIRouter.factory主要與用於指定具有靜態配置文件的中間件服務/處理管道的paste-deploy設計有關。

業界有着豐富的歷史,想象着可組合模塊的處理框架 - 插件體系結構令人印象深刻 - 將成爲建立網絡服務的可靠,高性能的方式,並且很有可能取得市場成功。這個夢想至少在20世紀80年代早期回溯到UNIX System V的STREAMS。插件體系結構經常有效 - 有時候很巧妙。然而,很少有這樣的框架取得成功,然而,獨立於其他原因已經非常成功的產品或供應商。那麼WordPress的插件系統,nginx,Apache或PostgreSQL?首都!一個插件系統應該在所有四個以及其他幾十個不同的引擎之間進行協調?可能是「一座橋太遠了」。但我的玩世不恭離題了。

工廠函數(或者這裏,工廠方法)在任何人想要決定使用什麼類型的對象而不依賴於繼承層次結構時都是有意義的。例如,想象一下API路由器的兩種實現:FastAPIRouter確實很快,但僅支持REST。 StandardAPIRouter速度較慢,但​​它支持REST或SOAP請求。如果你打電話FastAPIRouter()又名FastAPIRouter.__init__(),你可以只有得到一個FastAPIRouter實例。但是,如果您撥打FastAPIRouter.factory(...)並指示需要SOAP功能的參數,則該工廠方法可以選擇來替代返回StandardAPIRouter實例。你可能沒有得到你要求的確切的東西,但你找回了你所需要的東西。這通常更有價值。工廠是構造函數,但可以選擇子類來構造。標準構造函數不能選擇。

如果你不喜歡兄弟類中固有的緊密的coupling構造對方的實例,你可以想象一個對APIRouter.factory(...)的一般請求,它會產生一個「命令決定」,它的子類根據它的返回(推測是優越的)理解處理給定參數的最佳實現。還有耦合......但它提供了智能和價值。

這就像在一家餐廳,並要求錯誤的服務器的東西。一個可能的答案是「不,這不是我的桌子。」沒有客戶讚賞。更好的迴應是「傑克是你的服務器,我會幫你找到他。」這就是工廠方法可以做到的。它們不屬於課堂特殊方法的一部分;缺乏一個特定的,嚴格的構造函數,它們可以更加適應,甚至用一個更合適的對象代替最初請求的對象。

你偶爾會在Python中看到工廠。 collections.namedtuple是一個偉大的,有點神奇的例子。它不只是從預先存在的固定列表中選擇一個班級;它實際上根據您的規格從整塊布料中創建一個新班級。但是,像Python,Ruby,Perl和JavaScript這樣的動態語言並不像靜態類型語言那樣經常需要工廠。它們的構造函數與Java有相同的約束,但是這些語言也有動態類型(「後期綁定」),鴨子打字和開發人員像繼承一樣使用委託的意願。這組特徵給予了更多的自由度來選擇「正確的工作對象」。無論是技術需求還是文化選擇,Java開發人員都非常重視靈活性。

也考慮歷史:當今的許多中間件開發人員花費了大量時間在Java技術上和經濟上處理其龐大的生態系統。毫不奇怪,Java的「軟件工程」領域的模式和實踐,如測試,依賴注入和子系統組合已經傳播到其他語言社區。一旦模式,期望和行話建立良好,它們往往會持續下去。

因此,在Neutron中使用.factory()構造函數在技術上和其他方面都是有意義的。

但有一個「但......」幾個,其實。

  1. 我不能聲稱已經看到了世界上所有的Neutron代碼,但我看到的代碼實際上並沒有使用工廠。 APIRouter.factoryAPIRouter.__init__更具吸引力,呼叫順序稍有變化。與開發人員的敏感度和標準化的體系結構呼叫簽名保持一致 - 這些對他們來說是非常有價值的。但這是一個狹窄的技術性問題,因爲Neutron可以同樣指定標準構造函數的調用簽名。目前的工廠實際上並不使用他們的參數或增加智能。他們是備考工廠工廠,和事實上替代構造函數。

  2. 整個paste-deploy方法是在配置文件中指定你想要的組件。這導致人們明確地選擇所需的類,限制了靈活的「我們應該構建什麼樣的對象?」的需要和價值。代碼中的選擇。正如動態語言的自由度使工廠發光一樣,配置文件降低了工廠在中間件組成角色中的價值。

關於你的第二個問題,爲什麼在配置設置中未使用過?推測是因爲APIRouter不需要它們。其他幾個模塊(例如處理版本控制和IPAM可插入過濾器)似乎使用本地或全局配置對象(儘管只是在傳遞中)。我將未使用的配置選項粉刷成很像工廠方法:它們是構圖系統的架構特徵,實際上,它並不被大量使用,而這對於APIRouter來說恰好是不必要的。

摘要

工廠允許更靈活的創建對象。一種語言越拘泥於語言,工廠模式就越有必要。它們作爲插件框架或可擴展服務器的功能非常明智。但在這種特殊情況下,工廠非常輕巧而且經常使用。

即使工廠在當前代碼中使用得並不多,您可能會認爲它們有意義,因爲外部模塊或未來版本可能會更廣泛地使用。並非所有架構元素都需要最初用作框架的一部分。

+0

感謝您的回答。但我相信使用工廠而不是構造函數有一些優勢。我希望答案能夠說明這個優勢。更好的例子。 –

+0

@KramerLi我認爲工廠的價值是給定的,並且對這些工廠的價值嗤之以鼻,因爲它們基本上沒有使用。經過反思,我應該解釋他們可能的價值/作用,而不僅僅是他們目前(有限的)價值/角色。相應的重寫。 –

相關問題