ढलाई
यह लगभग निश्चित रूप से उद्धृत पुस्तक के दृष्टिकोण के लिए एक पूर्ण स्पर्शरेखा होने जा रहा है, लेकिन आईएसपी के लिए बेहतर तरीके से पुष्टि करने का एक तरीका QueryInterface
COM-शैली के दृष्टिकोण का उपयोग करके अपने कोडबेस के एक केंद्रीय क्षेत्र में एक कास्टिंग मानसिकता को गले लगाना है ।
शुद्ध इंटरफ़ेस संदर्भ में अतिव्यापी इंटरफेस डिजाइन करने के लिए बहुत सारे प्रलोभन अक्सर एक सटीक, स्नाइपर जैसी जिम्मेदारी से अधिक "आत्मनिर्भर" इंटरफेस बनाने की इच्छा से आते हैं।
उदाहरण के लिए, इस तरह से क्लाइंट फ़ंक्शन डिज़ाइन करना अजीब लग सकता है:
// Returns the absolute position of an entity as the sum
// of its own position and the position of its ancestors.
// `position` and `parenting` parameters should point to the
// same object.
Vec2i abs_position(IPosition* position, IParenting* parenting)
{
const Vec2i xy = position->xy();
auto parent = parenting->parent();
if (parent)
{
// If the entity has a parent, return the sum of the
// parent position and the entity's local position.
return xy + abs_position(dynamic_cast<IPosition*>(parent),
dynamic_cast<IParenting*>(parent));
}
return xy;
}
... साथ ही साथ बहुत बदसूरत / खतरनाक, यह देखते हुए कि हम इन इंटरफेस और / या एक ही वस्तु को एक तर्क के रूप में पारित करने के लिए क्लाइंट कोड में त्रुटि-प्रवण कास्टिंग करने के लिए ज़िम्मेदारी को लीक कर रहे हैं, उसी के कई मापदंडों के लिए समारोह। तो हम अंत में अक्सर जो की चिंताओं को समेकित किया गया है एक और अधिक पतला इंटरफेस डिजाइन करने के लिए चाहते हैं IParenting
और IPosition
की तरह, एक ही स्थान पर IGuiElement
है कि जो तब ओर्थोगोनल इंटरफेस जो वैसे ही के लिए और अधिक सदस्य कार्य करने के लिए परीक्षा हो जाएगा की चिंताओं के साथ अतिव्यापी के लिए अतिसंवेदनशील हो जाता है की तरह या कुछ और वही "आत्मनिर्भरता" कारण।
मिक्सिंग जिम्मेदारियाँ बनाम कास्टिंग
जब पूरी तरह से डिस्टिल्ड, अल्ट्रा-सिंगुलर जिम्मेदारी के साथ इंटरफेस डिजाइन करते हैं, तो प्रलोभन अक्सर या तो कई जिम्मेदारियों को पूरा करने के लिए कुछ डाउनकास्टिंग या समेकित इंटरफेस को स्वीकार करने के लिए होगा (और इसलिए आईएसपी और एसआरपी दोनों पर चलना)।
COM- शैली के दृष्टिकोण (केवल QueryInterface
भाग) का उपयोग करके , हम डाउनकास्टिंग दृष्टिकोण से खेलते हैं लेकिन कास्टिंग को कोडबेस में एक केंद्रीय स्थान पर समेकित करते हैं, और ऐसा कुछ और कर सकते हैं:
// Returns the absolute position of an entity as the sum
// of its own position and the position of its ancestors.
// `obj` should implement `IPosition` and optionally `IParenting`.
Vec2i abs_position(Object* obj)
{
// `Object::query_interface` returns nullptr if the interface is
// not provided by the entity. `Object` is an abstract base class
// inherited by all entities using this interface query system.
IPosition* position = obj->query_interface<IPosition>();
assert(position && "obj does not implement IPosition!");
const Vec2i xy = position->xy();
IParenting* parenting = obj->query_interface<IParenting>();
if (parenting && parenting->parent()->query_interface<IPosition>())
{
// If the entity implements IParenting and has a parent,
// return the sum of the parent position and the entity's
// local position.
return xy + abs_position(parenting->parent());
}
return xy;
}
... निश्चित रूप से टाइप-सेफ रैपर और उन सभी के साथ, जो आप कच्चे पॉइंटर्स की तुलना में कुछ सुरक्षित प्राप्त करने के लिए केंद्र बना सकते हैं।
इसके साथ, ओवरलैपिंग इंटरफेस को डिजाइन करने का प्रलोभन अक्सर पूर्ण न्यूनतम तक कम हो जाता है। यह आपको बहुत विलक्षण जिम्मेदारियों (कभी-कभी सिर्फ एक सदस्य कार्य के अंदर) के साथ इंटरफेस डिजाइन करने की अनुमति देता है जिसे आप आईएसपी के बारे में चिंता किए बिना सभी को मिला सकते हैं और मैच कर सकते हैं, और सी ++ में रनटाइम पर छद्म-बतख टाइपिंग का लचीलापन प्राप्त कर सकते हैं (हालांकि पाठ्यक्रम के साथ) वस्तुओं को क्वेरी करने के लिए रनटाइम पेनल्टी का व्यापार-बंद यह देखने के लिए कि क्या वे किसी विशेष इंटरफ़ेस का समर्थन करते हैं)। रनटाइम भाग महत्वपूर्ण हो सकता है, कहते हैं, एक सॉफ्टवेयर डेवलपमेंट किट के साथ एक सेटिंग जहां फ़ंक्शन में प्लगइन्स की संकलन-समय की जानकारी पहले से नहीं होगी जो इन इंटरफेस को लागू करते हैं।
टेम्पलेट्स
यदि टेम्प्लेट एक संभावना है (हमारे पास पहले से आवश्यक संकलन-समय की जानकारी है जो उस समय तक नहीं खो जाती है जब तक हम किसी वस्तु को पकड़ नहीं लेते हैं, अर्थात), तो हम बस यह कर सकते हैं:
// Returns the absolute position of an entity as the sum
// of its own position and the position of its ancestors.
// `obj` should have `position` and `parent` methods.
template <class Entity>
Vec2i abs_position(Entity& obj)
{
const Vec2i xy = obj.xy();
if (obj.parent())
{
// If the entity has a parent, return the sum of the parent
// position and the entity's local position.
return xy + abs_position(obj.parent());
}
return xy;
}
... निश्चित रूप से ऐसे मामले में, parent
विधि को उसी Entity
प्रकार वापस करना होगा , जिस स्थिति में हम संभवत: इंटरफेस से बचना चाहते हैं (क्योंकि वे अक्सर आधार बिंदुओं के साथ काम करने के पक्ष में प्रकार की जानकारी खोना चाहते हैं)।
इकाई-घटक प्रणाली
यदि आप COM- शैली के दृष्टिकोण को एक लचीलेपन या प्रदर्शन के दृष्टिकोण से आगे बढ़ाने लगते हैं, तो आप अक्सर उद्योग में गेम इंजन के समान एक इकाई-घटक प्रणाली के साथ समाप्त हो जाएंगे। उस बिंदु पर आप बहुत अधिक वस्तु-उन्मुख दृष्टिकोणों के लिए पूरी तरह से लंबवत होंगे, लेकिन ईसीएस जीयूआई डिजाइन पर लागू हो सकता है (एक जगह जिसे मैंने एक दृश्य-केंद्रित फोकस के बाहर ईसीएस का उपयोग करने पर विचार किया है, लेकिन इसे बहुत देर बाद माना गया एक COM शैली के दृष्टिकोण पर बसने की कोशिश)।
ध्यान दें कि यह COM- शैली समाधान पूरी तरह से वहाँ है जहाँ तक GUI टूलकिट डिज़ाइन चलते हैं, और ECS और भी अधिक होगा, इसलिए यह ऐसा कुछ नहीं है जो बहुत सारे संसाधनों द्वारा समर्थित होगा। फिर भी यह निश्चित रूप से आपको उन इंटरफेस को लुभाने की अनुमति देगा जो उन इंटरफेस को डिजाइन करने की ज़िम्मेदारी है, जिनकी जिम्मेदारियाँ पूरी तरह से कम हैं, अक्सर यह एक गैर-चिंता का विषय है।
व्यावहारिक दृष्टिकोण
विकल्प, ज़ाहिर है, अपने गार्ड थोड़ा आराम करें, या एक बारीक स्तर पर डिजाइन इंटरफेस और फिर उन्हें विरासत में मोटे इंटरफेस बनाने के लिए है कि आप का उपयोग करें, शुरू की तरह IPositionPlusParenting
है जो दोनों से व्युत्पन्न IPosition
औरIParenting
(उम्मीद है कि इससे बेहतर नाम के साथ)। शुद्ध इंटरफेस के साथ, यह आईएसपी का उल्लंघन नहीं करना चाहिए, क्योंकि उन अखंड गहरी-पदानुक्रमित दृष्टिकोण आमतौर पर लागू होते हैं (क्यूटी, एमएफसी, आदि, जहां प्रलेखन अक्सर अप्रासंगिक सदस्यों को छिपाने की आवश्यकता को देखते हुए आईएसपी का उल्लंघन करने के अत्यधिक स्तर को देखते हुए उन प्रकारों के साथ है। डिजाइन के), तो एक व्यावहारिक दृष्टिकोण बस यहाँ और वहाँ कुछ ओवरलैप स्वीकार कर सकते हैं। फिर भी इस तरह की COM- शैली का दृष्टिकोण आपके द्वारा उपयोग किए जाने वाले प्रत्येक संयोजन के लिए समेकित इंटरफेस बनाने की आवश्यकता से बचा जाता है। "आत्मनिर्भरता" की चिंता ऐसे मामलों में पूरी तरह से समाप्त हो जाती है, और यह अक्सर डिजाइन इंटरफेस के प्रलोभन के अंतिम स्रोत को समाप्त कर देगा जिसमें अतिव्यापी जिम्मेदारियां होती हैं जो एसआरपी और आईएसपी दोनों के साथ लड़ना चाहते हैं।