2016-01-19 125 views
1

用戶填寫表單並提交它。基於輸入,對象Organization被水合。我想從實際對象中分離與數據庫的通信。兩個相互依賴的類的構造函數注入

我想創建一個OrganizationMapper,它擁有數據庫通信(保存,刪除...)的方法。組織類將通過構造函數獲得OrganizationMapper

然而,對於這些類的定義,我不能實例化類,因爲它們相互依賴。

我該怎樣才能將數據庫通訊從Organization中分離出來並放入OrganizationMapper

class Organization 
{ 
    protected $id; 
    protected $name; 
    ... other properties ... 
    public function __construct(OrganizationMapper $mapper) 
    { 
     $this->mapper = $mapper; 
    } 
    public function getId() {...} 
    public function setId($id) {...} 
    ... other methods ... 
    public function saveToDb() 
    { 
     $this->mapper->save($this); 
    } 

OrganizationMapper

class OrganizationMapper 
{ 
    public function __construct(Organization $organization) 
    { 
     $this->organization = $organization 
    } 

    ... other methods 

    public function save($organization) 
    {... the code to use the methods of Organization class to save the data to the database...} 
} 

回答

3

這就是爲什麼循環依賴通常被認爲是一件壞事。


開玩笑不談,在我看來,你實際上並不需要在OrganizationMapper類的構造函數依賴。從它的外觀來看,無論如何,您都希望將作爲參數持續存在的Organization實例傳遞給映射器的save()方法,並且根本不需要該類中的實例屬性$this->organization

一般來說,我會盡量保持OrganizationMapper無狀態。儘量避免將實例存儲爲實例屬性(,尤其是,如果實際使用同一個映射器實例來持久化多個Organization)。只要按照save()方法那樣做,並將Organization對象作爲方法參數。


此外,我不會將Organization類與映射器相關聯。有人可能會認爲這違反了Single Responsibility Principle,因爲它不是課堂上堅持自己的責任。你可以移動這個邏輯來調用代碼,並有Organization類不知道在所有映射器(這是很好的,因爲你完全消除兩個類之間的循環依賴):

class Organization 
{ 
    protected $id; 
    protected $name; 
    // <other properties here> 

    // <getters and setters here> 
} 

class OrganizationMapper 
{ 
    public function save(Organization $organization) 
    { 
     // save $organization to DB, somehow 
    } 
} 

$organization = new Organization(); 
$organization->setName('Foobar International Inc.'); 

$mapper = new OrganizationMapper(); 
$mapper->save($organization); 
+0

謝謝!你提到我不需要mapper類中的構造函數。什麼時候有構造函數是好的?當映射程序有其他使用「組織」對象的方法? –

0

你不能在PHP中做到這一點。想象一下,如果它是可持有的。然後組織的實例將具有屬性OrganizationMapper,該屬性將具有屬性Organization。所以,類的一個實例屬性的屬性將是實例本身!它只能用像C++這樣的指針的語言。所以,我只看到2解決方案在這裏:

  • 把課一起上
  • 有一個鏈接(也許有1類,調用另一個,而第二個不首先調用。)
+0

嚴格來說,您也可以使用代理模擬PHP的行爲。 (例如,具有魔術__call方法的類並將每個調用轉發給稍後可以設置的委託)。在任何情況下,這是你不想做的事情;) –

2

要找到分隔條件這兩個問題的一個更好的辦法,想想你的兩個對象的目的:

  • 組織有沒有給你訪問一個組織
  • 的所有信息
  • 您的OrganizationMapper是否存在一個組織對象到數據庫。

當你想想這樣的,然後有幾個問題,那起來:

  • 爲什麼你組織需要saveToDb()方法?保存它不是工作嗎?
  • OrganizationMapper的一個實例應該可以將任何組織保存在數據庫中,那麼爲什麼你要兩次通過它? (一次在構造函數中,一次在保存($ organization)方法)。在這種情況下 - 如果將不同的組織傳遞給構造函數而不是保存方法,會發生什麼情況?
  • 在您當前的示例中,您將如何從數據庫加載組織?

作爲替代方案,我建議從組織刪除saveToDb()完全,因爲它不是組織本身保存到數據庫的工作。另外,我會從OrganizationMapper中刪除當前的構造函數。在目前的設計中,沒有理由將組織傳遞給構造函數。 另外,我會將OrganizationMapper重命名爲OrganizationRepository或OrganizationService。該類的主要目的不是將SQL映射到對象,而是將組織從數據庫檢索/保存到數據庫。 (另外,在OOP中,類只應遵循單一責任模式,所以也許SQL和對象之間的部分映射應該在特殊類中發生)

作爲一個方面說明:通常,給予許多人不是一個好主意如何做同樣的事情(例如拯救組織)。這可能會隨着時間推移而導致不一致(考慮到將來會添加一些驗證邏輯,但可能會忘記將其添加到第二位)。

我希望這可以幫助您:)

1

聲明:我命名你Organization類型,在這個崗位OrganizationEntity


很簡單,這是相反的方式。

OrganisationMapper得到一個OrganisationEntity對象,並通過手段可以選擇,將其保留到任何你想要的位置。

對於您的問題:

移動從OrganisationEntitysaveToDb()方法將OrganisationMapper並把它傳遞一個保存對象。

1

我不知道爲什麼Mapper應該對數據庫做任何操作? Mapper聽起來像將實體(組織)轉換成可以作爲數據庫操作輸入的東西,即。 Query Object。 您應該將您的班級重命名爲DAORepository。這將是更好的名字。

恕我直言,最好的辦法是將有:

  1. 組織作爲保持域邏輯對象
  2. OrganizationMapper應您的域對象轉換成某種查詢對象的
  3. OrganizationDao應採取組織作爲輸入參數並使用OrganizationMapper將其轉換並在數據庫上執行操作。

順便說一句,爲什麼你沒有使用某種類似於學說的ORM例如?它會讓你的生活更輕鬆:)

+0

謝謝,塞巴斯蒂安!你的意思是在這種情況下映射器將作爲一種中介對象,對吧?你可以做一個快速的代碼示例嗎?我實際上使用zf2,但我想了解如何在沒有ORM的情況下執行此操作。 –

+0

Mapper會將您的實體轉換爲可以輕鬆發送到數據庫的內容。 –