2010-08-07 93 views
3

我有一個設計問題,我無法找到一個乾淨漂亮的解決方案。我正在用PHP開發,但我相信這可能發生在任何語言。我的基本問題是我有兩個對象間有一定的循環相互依賴性。這意味着我有一個類(稱爲F)實現Facade模式,該模式包含一個對象(類B),它本身需要創建一個類A的對象。類A的構造函數本身需要創建一個外觀F =>我具有對象的循環相互依賴性。我相信我無法解決循環的相互依賴性(對象基本上用一個使用狀態模式的循環實現一個有限狀態機),所以我正在尋找一個乾淨的解決方案。我想出了兩種可能的解決方案我自己,但我不認爲要麼是特別優雅:創建相互依賴的對象

  1. 有A類實現setFacade(F $ facace)方法,並從構造刪除整個門面,只是設置後A和門面被創建。類A的對象不能在沒有外觀的情況下工作,所以這實際上會創建一個類A的對象,它在調用setFacade之前不能執行任何操作,它會減少封裝並允許在對象運行時替換外觀,我也不會不喜歡。

  2. 實現類似Promise的東西,它傳遞給A,而不是立面,它將在創建後立即解析立面。我不想介紹這個額外的間接層,特別是因爲我沒有很好的地方來解決這個承諾,而不是處理A內部的buisness邏輯的方法,這會產生可怕的錯誤和(更重要的)b)需要我檢查承諾是否已經解決,或者是否需要現在解決它,只要調用了buisness邏輯。這只是我眼中可怕的設計。

因此,如果任何人都可以想出更好的解決方案或可以支持我的一個可能的解決方案和一個很好的論證我真的很高興。

+0

它似乎違反了GRASP模式。您可能在爲課程分配責任時犯了一些錯誤。 – Kangkan 2010-08-07 17:44:02

+0

這當然是可能的。正如我所說,我基本上實現了一個有限狀態機。我有一個保存當前狀態的控制器(上下文)。只要控制器收到請求,它就會將其委託給該狀態,然後狀態將自行返回(如果它是循環狀態傳輸)或其他狀態(如果傳輸)。這個「其他國家」必須爲國家所知。如果兩個狀態以循環方式轉移到另一個狀態,這在FSM中是絕對常見的,那麼他們需要知道每個其他情況。 Bam - 循環依賴。 – 2010-08-07 18:02:29

回答

1

假設您使用的是Facade,因爲它是通常定義的(作爲一個簡化的接口來管理依賴關係,並且使得它更容易使用複雜的API),那麼沒有任何「隱藏的」(由外觀)類應該知道類其中使用了門面。基本上,把它看作單一的入口點,這或者意味着B不應該依賴於A,或者A不應該依賴於Facade。

+0

我使用術語Facade來表示一個子有限狀態機,它處理特別複雜的邏輯,並在邏輯完成後將其返回(傳送)回到更簡單的有限狀態機。 這個「轉回」實際上是創建循環依賴的地方。我可以重構依賴關係將它從B移到F,但它仍然會保留。另見我對康康評論的評論。 – 2010-08-07 18:06:12

+0

在你描述的情況下,我不認爲它是一個Facade。它看起來好像接近於一個Facade,但它看起來像A-> B-> F-> A(或者它掉出來)設計本質上是有缺陷的。我必須同意其他人的看法,感覺就像你需要回頭看看你的設計並確定如何區分這些依賴關係。 – EricBoersma 2010-08-07 18:30:28

+0

我只是看不出我還能如何建模一個循環的有限狀態機,在飛行中創建出口點不是可能的(出於各種原因)。我的系統看起來基本如此(http://www.danielbaulig.de/StateExample.png)。當然這很簡單。實際上F在各種不同的狀態下甚至更多的子機器上更復雜。我不能創建沒有F的A,不能創建沒有A的F(如果兩者在構造函數中都需要彼此)。我想不出有什麼辦法打破這種循環依賴。甚至可能沒有這樣的解決方案。 – 2010-08-07 19:04:38

2

循環依賴是這樣一種惡意的惡魔,他們必須不惜一切代價避免,即使這意味着完全重新考慮你的設計並且浪費了幾個小時的工作。 (從維護程序員的角度講,有些可憐的笨蛋,你需要這麼做)

有幾種方法可以查看重構代碼,但是我得到的簡短非特定的建議是任何對象導致循環依賴的應該將違規屬性,方法等分解成新對象。然後,兩個原始依賴關係中的每一個都依賴於這個第三個對象,而不是彼此關聯。 (並確保這第三個對象不依賴於原件。)

即使它意味着有重複或類似的代碼,它仍然比循環依賴性更好(但是,即使這適當的前期設計,這應該是可以避免的。 )

+0

我意識到這一點,但我不確定如何打破這種循環依賴 - 或者如果可能的話,因爲在我試圖建模的系統中存在循環依賴。 雖然我理解你的觀點 - 我自己是專業的維護程序員,儘管這個問題是關於私人項目的。 – 2010-08-07 18:09:18

+0

看過這個以及你的其他評論......它不像我描繪的那麼糟糕。不可取,但如果你正在建模的實際系統本身具有這種循環依賴性,那麼你可能正確建模。 – David 2010-08-07 18:20:01

1

雖然我無法解決我的循環依賴問題,但我至少在解決方案中解決了如何創建包含該循環依賴項的系統。

我改變了我所有的狀態類,不再在構造函數中取出它們的出口點,而是通過一個方法在第二次調用時基本拋出異常。

然後我引入了一個構建器類,它將在我的狀態機中創建每個狀態,然後使用上面解釋的方法設置它們的狀態傳輸連接。因此,只要構建器返回有限狀態機,它就完全安裝並準備好使用。每個狀態的退出點不能再被改變,因爲設置它們的方法會在調用時拋出異常,因爲構建器在創建有限狀態機時曾經調用它們。

謝謝大家幫助我解決這個問題。

+0

很高興爲您提供幫助,我認爲您的設置相當優雅。 – EricBoersma 2010-08-07 21:04:27