2012-09-11 17 views
6

मुझे लगता है कि मैं अपने कोड में किसी चीज़ का केस स्टडी का उपयोग उदाहरण के उदाहरण के रूप में करूँगा।इंटरफ़ेस विरासत/पदानुक्रम .Net में - क्या कोई बेहतर तरीका है?

अभी, मैं अपने घटक-आधारित गेम सिस्टम के लिए एक व्यवहार/क्रिया प्रणाली पर काम कर रहा हूं। GameObjects एक IBehaviorComponent और एक IActionComponent उन्हें संलग्न है, जो वह केवल प्रासंगिक विवरण दर्शाने हो सकता है, निम्नलिखित का पर्दाफाश:

public interface IBehaviorComponent : IBaseComponent 
{ 
    IBehavior Behavior { get; } 
} 

public interface IActionComponent : IBaseComponent 
{ 
    IAction Action { get; } 
    void ExecuteAction(IGameObject target = null); 
} 

अब, यह अब तक सब ठीक है (कम से कम मेरे लिए!)। लेकिन, जब मैं IActionComponent के कार्यान्वयन को देखता हूं तो परेशानी पैदा होती है।

उदाहरण के लिए, एक साधारण IActionComponent कार्यान्वयन:

public class SimpleActionComponent : IActionComponent 
{ 
    public IAction Action { get; protected set; } 

    public void ExecuteAction(IGameObject target = null) 
    { 
     Action.Execute(target); 
    } 

    public void Update(float deltaTime) { } //from IBaseComponent 
} 

लेकिन, चलो कहते हैं कि मैं एक अधिक जटिल IActionComponent कार्यान्वयन कार्यों के लिए एक समय समय पर निष्पादित किया जा करने की अनुमति देता है कि लागू करने के लिए चाहते हैं:

public class TimedActionComponent : IActionComponent 
{ 
    public IAction Action { get; protected set; } 

    public float IdleTime { get; set; } 

    public float IdleTimeRemaining { get; protected set; } 

    public void ExecuteAction(IGameObject target = null) 
    { 
     IdleTimeRemaining = IdleTime; 
    } 

    public void Update(float deltaTime) 
    { 
     if (IdleTimeRemaining > 0f) 
     { 
     IdleTimeRemaining -= deltaTime; 
     } 
     else 
     { 
     Action.Execute(target); 
     } 
    } 
} 

और अब, मान लें कि मैं IdleTime का पर्दाफाश करना चाहता हूं ताकि इसे बाहरी प्रभावों से बदला जा सके।

public interface ITimedActionComponent : IActionComponent 
{ 
    float IdleTime { get; set; } 

    float IdleTimeRemaining { get; set; } 
} 

हालांकि, यहां मुद्दा यह है कि मेरे घटक प्रणाली IBaseComponent से एक स्तर ऊपर से सब कुछ संग्रहीत करता है: पहली बार में मेरे विचार एक नया इंटरफेस बनाने के लिए थे। इसलिए, GameObject के लिए एक्शन घटक को IActionComponent के रूप में पुनर्प्राप्त किया जाता है, जैसा कि, कहता है, एक ITimedActionComponent, या एक IRandomizedActionComponent, या यहां तक ​​कि एक ICrashTheProgramActionComponent भी। मुझे उम्मीद है कि इसके कारण स्पष्ट हैं, क्योंकि मैं किसी भी घटक के लिए GameObject से पूछताछ करने में सक्षम होना चाहता हूं, यह जानने के बिना कि वह मूल प्रकार के घटक (IActionComponent, IRenderableComponent, IPhysicsComponent, आदि) से परे क्या चाहता है,

क्या इसका संचालन करने का एक क्लीनर तरीका है, जो मुझे इन वर्गों में परिभाषित इन गुणों को बेनकाब करने की इजाजत देता है, बिना किसी चीज के प्राप्त किए गए IActionComponent को पुनर्प्राप्त करने के लिए? या यह केवल इसे पूरा करने का एकमात्र/सर्वोत्तम तरीका है। कुछ की तरह:

public void IWantYouToAttackSuperSlow(IGameObject target) 
{ 
    //Let's get the action component for the gameobject and test if it's an ITimedActionComponent... 
    ITimedActionComponent actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent; 

    if (actionComponent != null) //We're okay! 
    { 
     actionComponent.IdleTime = int.MaxValue; //Mwhaha 
    } 
} 
अभी

मुझे लगता है कि सिर्फ़ इसी में सोच रहा हूँ, लेकिन मैं समझ वहाँ एक पैटर्न लकड़ी है कि मैं से अनभिज्ञ हूँ, या में छिपा है अगर मैं देखना चाहते हैं किसी को भी एक सुझाव दे सकते हैं यदि शुरू करने के लिए इसे पूरा करने का एक बेहतर तरीका है।

धन्यवाद!

+0

मेरे दूसरे सोचा इस तरह के IActionComponentExecutor के रूप में है, जो होगा, अंदर किसी अन्य वस्तु का उपयोग किया गया तय करें कि कार्रवाई कब करें। निष्पादित करें(), लेकिन मुझे लगता है कि मुझे एक गोल-ए-बाउट फैशन में स्क्वायर वन पर वापस लाता है - बाहरी ऑब्जेक्ट्स को तब IActionComponentTimedExecutor को ट्रैक करना होगा (ओह ~ हम gettin 'एंटरप्राइज़- y !) IdleTime बदलने के लिए। – Terminal8

+0

ब्याज से - कार्रवाई के लिए राज्य कॉम्पोनेंट.इडलटाइम किसी प्रकार के जेनेरिक बैग में संग्रहीत है? यदि ऐसा है तो आप अपने बेस इंटरफेस पर 'लागू (बैगडाटा बैग)' और 'स्टोर (बैगडाटा बैग)' विधियां कर सकते हैं। उस ने कहा, आपको कुछ मेटाडेटा-प्रकार सिस्टम पर भी विचार करने की आवश्यकता हो सकती है जिसे आप व्युत्पन्न प्रकारों को जानने की आवश्यकता वाले गुणों के लिए उपयोग कर सकते हैं। 'टाइपडिस्क्रिप्टर' एक तैयार रोल वाला प्रारंभिक बिंदु है जिसका उपयोग संपत्ति ग्रिड इत्यादि जैसी चीजों द्वारा किया जाता है। –

+0

नहीं, वर्तमान में यह नहीं है। मैं अवधारणा से पूरी तरह से परिचित नहीं हूं - क्या कोई संदर्भ है जो आप शायद प्रदान कर सकते हैं? – Terminal8

उत्तर

0

आप सही हैं, उपप्रकारों को कास्टिंग करके एक विशिष्ट कार्यान्वयन के लिए परीक्षण करना एक अच्छा विचार नहीं है। आपके द्वारा प्रदान किए गए उदाहरणों से ऐसा लगता है कि आपके पास IGameObject है जिसे आप कुछ क्रियाएं करना चाहते हैं। IActionComponent को एक विधि का पर्दाफाश करने के बजायको तर्क के रूप में लेते हैं, तो आप इसे अन्य तरीकों से सॉर्ट कर सकते हैं, यानी IGameObject यदि आप चाहें तो एक या कई ले जाएं, जो क्रियाएं आप निष्पादित कर सकते हैं।

interface IActionComponent 
{ 
    ExecuteAction(); 
} 

interface IGameObject 
{ 
    IActionComponent ActionComponent { get; } 
} 
तो क्रियान्वित विधि में

public void IWantYouToAttackSuperSlow(IGameObject target) 
{ 
    target.ActionComponent.ExecuteAction(); 
} 

करना कैसे आप IActionComponent लागू के आधार पर, बहुरूपता सुनिश्चित करें कि सही कोड निष्पादित कर देगा।

Command Pattern नामक एक पैटर्न है जो आपकी आवश्यकता के अनुरूप लगता है।

+0

आह, मैंने जो केस स्टडी प्रदान की है, वह इस इंटरफ़ेस विरासत समस्या का केवल एक उदाहरण था जिसमें मैं दौड़ रहा हूं। चूंकि मैं एक घटक-आधारित प्रणाली विकसित कर रहा हूं, IGameObject * केवल * घटकों के लिए एक बेहद सरल कंटेनर है, जिसमें किसी भी "वास्तविक" घटकों के बारे में बिल्कुल कोई तर्क या ज्ञान नहीं है। संक्षेप में, यह केवल एक GUID है जो घटकों को उस 'इकाई' से बंधने के लिए एक 'इकाई' को कवर करने की अनुमति देता है (लेकिन मैंने उस अवधारणा को इंटरफ़ेस/कक्षा में आसान घटक पुनर्प्राप्ति प्रदान करने के लिए encapsulated किया है)। – Terminal8

+0

@Icelight: मैं पूरी तरह से अपने वास्तुकला को समझने का दावा नहीं कर सकता। हालांकि, आपकी सजा * "IGameObject केवल घटकों के लिए एक बेहद सरल कंटेनर है, बिल्कुल कोई तर्क नहीं .." * मुझे अजीब लगता है। जब भी मैं एक वर्ग के बारे में सुनता हूं कि 'केवल किसी भी तर्क के बिना गुणों का एक बैग होना चाहिए', मुझे ऑब्जेक्ट उन्मुख प्रोग्रामिंग के बारे में पहली चीज़ के बारे में पता चला है: यह ** व्यवहार ** डालने के बारे में है जहां ** डेटा ** है। तो, मेरी राय में, तर्क-रहित वर्ग कोड गंध का थोड़ा सा हिस्सा हैं। –

+0

@ एसजोनी: मैं समझता हूं कि आप क्या प्राप्त कर रहे हैं। हालांकि, इस मामले में, आवश्यकता के बजाए, मेरी सुविधा के लिए गेमऑब्जेक्ट लगाया गया था। एक "सच्चे" घटक आधारित गेम सिस्टम में, सभी घटक बड़े बड़े घटक क्लाउड (या अधिक संभावना है, उनके घटक प्रकार को समर्पित प्रबंधकों में बैठे हुए) में चारों ओर तैर रहे होंगे, केवल कुछ GUID टाईंग वाले हैं एक ही इकाई के साथ मिलकर। इस दृष्टिकोण को लेने के बजाय मैं गेमऑब्जेक्ट का उपयोग कर रहा हूं जिसमें एक ही इकाई के सभी घटक हैं - सुविधा, क्योंकि इस दृष्टिकोण को मेरे लिए कल्पना करना आसान है। – Terminal8

1

कोड आप से पता चला कि डाले नीचे एक IActionComponent के लिए एक ITimedActionComponent है (जहाँ तक मैं देख सकते हैं) unavoidable- आप उन्हें का उपयोग करने के IdleTime गुण के बारे में पता होना चाहिए, है ना?

मुझे लगता है कि यह चाल उस छिपे हुए दिखने वाले कोड को छिपाने के लिए होगी जहां आपके IActionComponent का उपयोग करने वाले वर्गों को इसका सामना नहीं करना पड़ेगा।
ऐसा करने के तरीके पर मेरी पहली सोचा उपयोग करने के लिए है एक Factory:

public void IWantYouToAttackSuperSlow(IGameObject target) 
{ 
    //Let's get the action component for the gameobject 
    IActionComponent actionComponent = ActionComponentsFactory.GetTimedActionComponentIfAvailable(int.MaxValue); 
} 

और अपने कारखाने की विधि:

public IActionComponent GetTimedActionComponentIfAvailable(IGameObject target, int idleTime) 
{ 
var actionComponent = target.GetComponent<IActionComponent>() as ITimedActionComponent; 

    if (actionComponent != null) //We're okay! 
    { 
     actionComponent.IdleTime = int.MaxValue; //Mwhaha 
    } 
return (actionComponent != null)? actionComponent : target.GetComponent<IActionComponent>(); 
} 
+0

आपकी पहली वाक्य के संबंध में - मैं सहमत हूं, और मुझे इसके आसपास कोई वास्तविक तरीका नहीं दिख रहा है। मुझे लगता है कि मैं मछली पकड़ने/कुछ चमत्कार वास्तुकला के लिए प्रार्थना कर रहा था जो सब कुछ ठीक करेगा। लेकिन मुझे लगता है कि हम अभी तक काफी नहीं हैं;) फैक्ट्री विधि के लिए, मुझे यह पसंद है, और यह कम से कम चीजों को साफ करने में मदद करेगा। मैं यह देखने के लिए जा रहा हूं कि यह मेरे पास अभी क्या काम करेगा। – Terminal8

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