2010-10-24 54 views
18

我目前正在設計我的類時遇到循環依賴關係問題。自從我閱讀了關於Anemic Domain Model(我一直在做的事情)之後,我一直試圖擺脫創建只是「getters和setter桶」的域對象,並返回到我的OO根。面向對象設計和循環依賴關係

但是,下面的問題是我遇到了很多,我不知道我應該如何解決它。

假設我們有一個團隊類,即有很多玩家。無論這是什麼運動都無所謂:)一個球隊可以添加和移除球員,就像球員可以離開球隊並加入另一個球員一樣。

因此,我們有團隊,其中有球員名單:

public class Team { 

    private List<Player> players; 

    // snip. 

    public void removePlayer(Player player) { 
     players.remove(player); 
     // Do other admin work when a player leaves 
    } 
} 

然後我們有播放器,它具有對團隊參考:

public class Player { 
    private Team team; 

    public void leaveTeam() { 
     team = null; 
     // Do some more player stuff... 
    } 
} 

我們可以假定這兩個方法(移除和離開)具有領域特定的邏輯,當團隊移除球員並且球員離開球隊時需要運行領域特定的邏輯。因此,我首先想到的是,當團隊踢的球員,removePlayer(...)也應調用player.leaveTeam()方法...

那麼是什麼,如果球員是驅動離開 - 應該leaveTeam()方法調用team.removePlayer(this)?不是沒有創建一個無限循環!

在過去,我只是讓這些對象「啞」POJOs和有一個服務層做的工作。但即使是現在我還是留下了這個問題:爲了避免循環依賴,服務層仍具有鏈接它一起 - 即

public class SomeService { 

    public void leave(Player player, Team team) { 

     team.removePlayer(player); 
     player.leaveTeam(); 

    } 

} 

我是不是在複雜嗎?也許我錯過了一些明顯的設計缺陷。任何反饋將不勝感激。


感謝所有的回覆。我接受Grodriguez的解決方案,因爲它是最明顯的(不能相信它不會發生在我身上)並且易於實現。然而,DecaniBass確實是一個很好的觀點。在我所描述的情況下,球員可能會離開球隊(並且知道他是否在球隊中)以及推動球隊移動的球隊。但我同意你的觀點,我不喜歡這個過程中有兩個「切入點」的想法。再次感謝。

回答

14

您可以通過添加警衛來檢查團隊是否仍然有玩家/玩家仍然在隊伍中,從而打破循環依賴。例如:

Team類:

public void removePlayer(Player player) { 
    if (players.contains(player)) 
    { 
     players.remove(player); 
     player.leaveTeam(); 
     // Do other admin work when a player leaves 
    } 
} 

Player類:

public void leaveTeam() { 
    if (team != null) 
    { 
     team.removePlayer(this); 
     team = null; 
     // Do some more player stuff.. 
    } 
} 
+2

可能只是我而已,但我喜歡儘可能保守地使用if ... else。我注意到它使得代碼不易維護 – 2010-10-24 09:50:17

+4

players.remove()將在集合被更改時返回true;不需要執行.contains()。 – KarlP 2010-10-24 10:12:49

+0

@KarlP:我知道,但我認爲明確的檢查會使邏輯更加清晰。 – Grodriguez 2010-10-24 10:26:52

1
public void removePlayer(Player player) { 
    if (players.contains(player)) { 
     players.remove(player); 
     player.leaveTeam(); 
    } 
} 

同上leaveTeam

2

想法是做不同的方法域相關的東西不打電話給對方,但確實域相關爲自己的對象的東西,即團隊的方法是否適合團隊和球員的方法是否適合球員

public class Team { 

    private List<Player> players; 

    public void removePlayer(Player player) { 
     removePlayerFromTeam(player); 
     player.removeFromTeam(); 
    } 
    public void removePlayerFromTeam(Player player) { 
     players.remove(player); 
     //domain stuff 
    } 
} 

public class Player { 
    private Team team; 

    public void removeFromTeam() { 
     team = null; 
     //domain stuff 
    } 
    public void leaveTeam() { 
     team.removePlayerFromTeam(this); 
     removeFromTeam(); 
    } 

} 
+1

當你打電話時,'leaveTeam()'方法會拋出一個NPE 'team = null'後設置'team.removePlayerFromTeam()'。 – Grodriguez 2010-10-24 08:06:37

+0

同樣在這個解決方案中,調用'player.leaveTeam()'實際上並不會從團隊對象中的玩家列表中移除玩家。同樣,調用'team.removePlayer()'也不會在播放器對象中將'team' var設置爲'null'。 – Grodriguez 2010-10-24 08:08:30

+1

在這個設計中,我認爲包含域特定代碼的方法應該是包私有的,而不是公開的。但這絕對是我想要的路線。 – Waldheinz 2010-10-24 09:25:12

7

本,

我會開始問一個球員是否可以(合乎邏輯地,合法地)從球隊中解脫出來。我會說玩家對象不知道他在哪個隊(!),他是一個團隊的一部分。因此,請刪除Player#leaveTeam(),並通過Team#removePlayer()方法進行所有團隊更改。

在你只有一個球員,需要從它的團隊中取出的情況下,那麼你可能會對團隊public static Team findTeam(Player player) ...

我知道這是不是一個Player#leaveTeam()方法不太令人滿意的,自然的靜態查找方法,但以我的經驗,你仍然可以擁有一個有意義的領域模型。

2的方式引用(父 - >兒童和兒童安全>家長)往往與其他事物充滿,說垃圾收集,維持「參照完整性」等

設計是一種妥協!