2011-01-18 20 views
9

我正在OO PHP中的社交網絡類型項目工作,我不想使用現有的框架。做這個項目的主要目的是幫助我瞭解更多的東西。這是太多依賴注入通過構造函數的對象?

這個問題更多的是依賴注入。

比方說,我有這些類:

核心類 - 一些核心的方法做的東西在應用
配置類 - 負載現場配置的東西
數據庫類 - 連接到MySQL並做所有數據庫相關的東西
記錄器類 - 用於記錄錯誤和調試信息
驗證碼類 - 對形式的驗證碼
會話類 - 發起會話的開始,並添加,刪除,獲取會話變量在該應用使用
緩存類 - 類似於會話類,但對於緩存項(文件緩存,memcache,apc緩存。我甚至可能會將我的會話內容添加到此類中,因爲所有這些緩存都可以使用相同類型的方法)

上述所有類都很可能用於我的應用中的每個頁面加載(我可能錯過了更多類將在稍後添加)

現在除了需要注入大多數其他類的上述類之外,我還會有許多更多的類。我將有一個secion稱爲模塊,這將有這樣的東西......

賬戶類 - 創建新用戶,認證用戶,用戶登錄和退出應用程序,更新用戶設置,以及更多。
用戶類 - 顯示用戶的配置文件,顯示用戶在線,新用戶,所有的東西,以顯示該網站的用戶
論壇類 - 將成爲論壇的部分
博客類 - 在博客部分
照片類 - 所有的照片相關的東西
評論類 - 處理意見的相片和個人資料

將有更多這些類型的網站的不同部分的類。
上面列出的第二組課程將很可能需要將第一組中的大部分類注入到其中。

所以我應該使用註冊表來存儲第一組類中的對象,並將註冊表注入到第二組類中的所有類對象中?

或者我應該使用構造函數來加載它們?在這個例子中,會有7個對象注入其他類,這看起來很多。我是否在談論這個錯誤?

---編輯---
我知道Singleton模式的,但我不認爲這是我在這裏的最佳選擇

--- EDIT 2 ---
正如有些人所說,需要傳入多達7個對象看起來像是很多,這就是爲什麼我正在尋找建議。幸運的是,這個項目正處於起步階段,所以現在是改變結構的時候了。

一個例子是我的論壇部分的一個類。論壇類將需要訪問會話數據,可能的緩存數據,配置對象,數據庫對象。 AM我以這種錯誤的方式去做?

+0

相關:http://stackoverflow.com/questions/2420193/dependency-injection-constructor-madness – 2011-01-18 20:49:15

+0

刪除我的回覆,因爲你也提到它。使用註冊表模式。 – mhitza 2011-01-18 20:50:49

+0

如果你的對象需要注入7個對象才能運行,我會挑戰這些類本身的底層架構。理想情況下,你應該只需要幾個對象。或者,依賴注入容器可能會緩解一些壓力。個人而言,我不是粉絲。 – CaseySoftware 2011-01-18 21:14:44

回答

11

或者我應該使用構造函數來加載它們?在這個例子中,會有7個對象注入其他類,這看起來很多。我是否在談論這個錯誤?

當您開始需要注入許多對象時,您需要詢問接收它們的對象是否過於負責。它可以分解成更小的碎片嗎?

如果確實不行,那麼考慮將相關對象封裝在另一個類中。也許你的session,logger和config對象可以注入到AppApplication對象中?

編輯:我注意到到目前爲止大多數其他答案都是關於單身人士。請注意單身人士是DI的敵人。關於這個here偉大的谷歌技術談話。

編輯2:

我的意思是通過封裝IS,而不是注入SessionLoggerConfig等所有到您Account類是什麼,也許他們應該被注入Application類和Application實例可以注入Account

說實話,這仍然是一塊DI我正在環繞我,但我開始看到的是這樣的:你應該只注入到Account它將直接需要操作的對象。這些對象可能需要操縱其他對象,但Account不需要知道它。


通常,你會發現你甚至不需要像你想象的那麼多的「圖層」。如果你發現你正在注入各種各樣的東西,考慮重新構建你的應用程序的各種方法。讓我拉了一段代碼從塔上的文檔模型:

a = model.Person() 
a.name = "Aaa" 
a.email = "[email protected]" 
meta.Session.add(a) 

(不要擔心meta.Session ...基本上它處理與數據庫交互)

在這裏,我們實例化一個Person,設置它的一些屬性,然後保存它。你會注意到Person類知道什麼都沒有關於數據庫,並且實際上甚至沒有save()方法。相反,我們將它傳遞給保存它的數據庫類(meta.Session)。我們已經從數據庫代碼中分離了對Person邏輯的關注。 meta.Session可以工作十幾種不同的方式,但只要它知道如何閱讀Person,我們都很好。 (在這種情況下,在應用程序初始化期間,它讀取所有應用程序模型的定義)。


好吧,我要總結一下,因爲我明顯在這裏漫步很多。對於你的問題沒有一個「正確的」答案(據我所知,但我並不以任何方式宣稱是DI專家)。

是,注入幾個對象可能是一些需要進行重組的指示,但你有一些注意事項,使:

  • 正在接受負責過多注射的對象;它可以分離出來嗎?
  • 您是否只注入收件人類將直接需要使用的對象?
  • 您是否注入了錯誤的方向;可以將Account對象注入到Database而不是其他方式嗎?
-2

我一直傾向於註冊表方式。

原因:

  • 更大的範圍
  • 簡單獲得
  • 構造是由具有對象作爲變量(可以更好的使用)
  • 允許你使用你的類更多的對象爲您免費獲釋當你想要的時候抓住你需要的東西。

雖然還有另一種方法,你可以嘗試使用單例模式,在每個類中都有一個方法來跟蹤它自己的對象。

福爾例如,創建一個接口,像這樣:

interface ISingleton 
{ 
    public static getInstnace(); 
} 

然後在每一個對象,你可以添加用於實例的獲取方法。

class SomeObject implements ISingleton, ISomeThingElse 
{ 
    private static $_instance; 
    public static getInstance() 
    { 
     if(self::$_instance === null) 
     { 
      self::$_instance = new SomeObject(); 
     } 
     return self::$_instance; 
    } 
} 

這樣,您始終保持對象的同一個實例以及具有全局範圍。

例子:

public function GetUser($id) 
{ 
    return Database::getInstance()->fetchUserById($id); 
} 

希望這有助於。


還有另一種方法,你可以做,這就是創建一個上下文類,讓我試着解釋:

類會像一個註冊表,但一次性的,例如:

class Context 
{ 
    private $objects = array(); 

    public function Add($key,$Object) 
    { 
     $this->objects[$key] = $object; 
    } 

    public function __get($key) 
    { 
     return isset($this->objects[$key]) ? $this->objects[$key] : null; 
    } 
} 

和使用,作爲容器來保存你的對象,像這樣:

$Context = new Context(); 
$Context->Add("database",$database); 
$Context->Add("logger",$logger); 
$Context->Add("session",$session); 

$UserObject = new RegularUser($Context); 

這種方式可以將一組對象分組並將相同的上下文傳遞給其他幾個庫對象。

相關問題