2010-10-24 24 views
18

मैं वर्तमान में अपनी कक्षाओं को डिजाइन करते समय एक परिपत्र निर्भरता समस्या के साथ संघर्ष कर रहा हूं।ओओ डिजाइन और परिपत्र निर्भरता

जब से मैंने Anemic Domain Model (कुछ मैं हर समय कर रहा था) के बारे में पढ़ता हूं, तो मैं वास्तव में डोमेन ऑब्जेक्ट्स बनाने से दूर जाने की कोशिश कर रहा हूं जो "गेटर्स और सेटर्स की बाल्टी" थी और मेरी ओओ जड़ों पर लौट आया।

हालांकि, नीचे दी गई समस्या वह है जो मैं बहुत से आती हूं और मुझे यकीन नहीं है कि मुझे इसे कैसे हल करना चाहिए।

कहें कि हमारे पास टीम कक्षा है, जिसमें कई खिलाड़ी हैं। इससे कोई फर्क नहीं पड़ता कि यह कौन सा खेल है :) एक टीम खिलाड़ियों को जोड़ और निकाल सकती है, वैसे ही एक खिलाड़ी एक टीम छोड़ सकता है और दूसरे में शामिल हो सकता है।

तो हम टीम है, जो खिलाड़ियों की एक सूची है है:

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() विधि ...

लेकिन तब क्या ड्राइविंग अगर प्लेयर है प्रस्थान - छुट्टी टीम() विधि कॉल टीम चाहिए .removePlayer (यह)? अनंत लूप बनाने के बिना नहीं!

पिछले में, मैंने इन वस्तुओं को "गूंगा" POJO बना दिया होगा और एक सेवा परत काम करेगी। लेकिन अब भी मैं अभी भी है कि समस्या के साथ छोड़ दिया है: परिपत्र निर्भरता से बचने के लिए, सेवा परत अभी भी यह सब एक साथ लिंक है - यानी

public class SomeService { 

    public void leave(Player player, Team team) { 

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

    } 

} 

मैं इस उलझी हूँ? शायद मैं कुछ स्पष्ट डिजाइन दोष खो रहा हूँ। किसी भी प्रतिक्रिया की काफी सराहना की जाएगी।


सभी प्रतिक्रियाओं के लिए धन्यवाद। मैं ग्रोड्रिगेज के समाधान को स्वीकार कर रहा हूं क्योंकि यह सबसे स्पष्ट है (विश्वास नहीं कर सकता कि यह मेरे साथ नहीं हुआ) और कार्यान्वित करने में आसान है। हालांकि, 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

यह सिर्फ मेरा हो सकता है, लेकिन अगर मैं जितना संभव हो उतना कम से कम उपयोग करना चाहता हूं। मैंने देखा है कि यह कोड को थोड़ा कम रखरखाव करने योग्य बनाता है –

+4

players.remove() संग्रह बदल दिया गया था, तो सत्य वापस आ जाएगा; .contains() करने की कोई ज़रूरत नहीं है। – KarlP

+0

@ करलप: मुझे पता है, लेकिन मैंने सोचा कि स्पष्ट जांच तर्क को और स्पष्ट करेगी। – Grodriguez

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()' विधि एक एनपीई फेंक देगा जैसा कि आप कॉल करते हैं 'टीम = नल'' सेट करने के बाद 'team.removePlayerFromTeam()'। – Grodriguez

+0

इसके अलावा, इस समाधान में, 'player.leaveTeam()' को कॉल करना वास्तव में टीम ऑब्जेक्ट में प्लेयर की सूची से प्लेयर को नहीं हटाता है। इसी प्रकार, 'team.removePlayer()' को कॉल करने से खिलाड़ी ऑब्जेक्ट में 'टीम' var 'null' को सेट नहीं किया जाएगा। – Grodriguez

+1

इस डिज़ाइन में डोमेन-विशिष्ट कोड वाले विधियां पैकेज-निजी और सार्वजनिक नहीं होनी चाहिए, मुझे लगता है। लेकिन यह निश्चित रूप से वह मार्ग है जो मैं लेता हूं। – Waldheinz

7

बेन,

मैं यह पूछकर शुरू करूंगा कि कोई खिलाड़ी टीम से खुद को हटा सकता है (तर्कसंगत रूप से, कानूनी रूप से)। मैं कहूंगा कि खिलाड़ी ऑब्जेक्ट नहीं जानता कि वह किस टीम में है (!), वह एक टीम का हिस्सा है। तो, Player#leaveTeam() हटाएं और सभी टीम परिवर्तन Team#removePlayer() विधि के माध्यम से करें।

मामले में जहां आप केवल एक खिलाड़ी है और अपनी टीम से हटाने के लिए की जरूरत में, तो आप टीम public static Team findTeam(Player player) ...

मैं जानता हूँ कि यह कम संतोषजनक है और एक Player#leaveTeam() विधि की तुलना में स्वाभाविक है पर एक स्थिर देखने विधि हो सकता था, लेकिन मेरे अनुभव में आप अभी भी एक सार्थक डोमेन मॉडल कर सकते हैं।

2 रास्ता संदर्भ (जनक -> बच्चे और बच्चे के> जनक) अक्सर अन्य बातों से भरा रहे हैं, कहते हैं कि कूड़ा संग्रह, "रेफेरेंन्शिअल सत्यनिष्ठा" को बनाए रखने, आदि

डिजाइन एक समझौता है!

संबंधित मुद्दे