म्यूटेशन विधियों के लिए अलग इंटरफ़ेस


11

मैं कुछ कोड को रीक्रिएट करने पर काम कर रहा हूं, और मुझे लगता है कि मैंने खरगोश के छेद के नीचे पहला कदम उठाया हो सकता है। मैं जावा में उदाहरण लिख रहा हूं, लेकिन मुझे लगता है कि यह अज्ञेयवादी हो सकता है।

मेरे पास एक इंटरफ़ेस के Fooरूप में परिभाषित है

public interface Foo {

    int getX();

    int getY();

    int getZ();
}

और एक कार्यान्वयन के रूप में

public final class DefaultFoo implements Foo {

    public DefaultFoo(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getZ() {
        return z;
    }

    private final int x;
    private final int y;
    private final int z;
}

मेरे पास एक इंटरफ़ेस भी है जो MutableFooमिलान म्यूटेटर प्रदान करता है

/**
 * This class extends Foo, because a 'write-only' instance should not
 * be possible and a bit counter-intuitive.
 */
public interface MutableFoo extends Foo {

    void setX(int newX);

    void setY(int newY);

    void setZ(int newZ);
}

वहाँ कार्यान्वयन के कुछ जोड़े MutableFooमौजूद हो सकते हैं (मैंने उन्हें अभी तक लागू नहीं किया है)। उनमें से एक है

public final class DefaultMutableFoo implements MutableFoo {

    /**
     * A DefaultMutableFoo is not conceptually constructed 
     * without all values being set.
     */
    public DefaultMutableFoo(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public int getX() {
        return x;
    }

    public void setX(int newX) {
        this.x = newX;
    }

    public int getY() {
        return y;
    }

    public void setY(int newY) {
        this.y = newY;
    }

    public int getZ() {
        return z;
    }

    public void setZ(int newZ) {
        this.z = newZ;
    }

    private int x;
    private int y;
    private int z;
}

मेरे द्वारा विभाजित किए जाने का कारण यह है क्योंकि यह प्रत्येक के लिए समान रूप से उपयोग किए जाने की संभावना है। मतलब, यह समान रूप से संभावना है कि इन वर्गों का उपयोग करने वाला कोई व्यक्ति एक अपरिवर्तनीय उदाहरण चाहता है, क्योंकि यह वह है जो एक परिवर्तनशील चाहते हैं।

प्राथमिक उपयोग-मामला जो मेरे पास है वह एक इंटरफ़ेस है जिसे StatSetगेम (हिट पॉइंट, अटैक, डिफेंस) के लिए कुछ निश्चित विवरणों का प्रतिनिधित्व करता है। हालांकि, "प्रभावी" आँकड़े, या वास्तविक आँकड़े, आधार आँकड़ों के परिणामस्वरूप होते हैं, जिन्हें कभी नहीं बदला जा सकता है, और प्रशिक्षित आँकड़े, जिन्हें बढ़ाया जा सकता है। इन दोनों से संबंधित हैं

/**
 * The EffectiveStats can never be modified independently of either the baseStats
 * or trained stats. As such, this StatSet must never provide mutators.
 */
public StatSet calculateEffectiveStats() {
    int effectiveHitpoints =
        baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
    int effectiveAttack = 
        baseStats.getAttack() + (trainedStats.getAttack() / 4);
    int effectiveDefense = 
        baseStats.getDefense() + (trainedStats.getDefense() / 4);

    return StatSetFactory.createImmutableStatSet(effectiveHitpoints, effectiveAttack, effectiveDefense);
}

प्रशिक्षित स्टैट्स को हर लड़ाई की तरह बढ़ाया जाता है

public void grantExperience() {
    int hitpointsReward = 0;
    int attackReward = 0;
    int defenseReward = 0;

    final StatSet enemyStats = enemy.getEffectiveStats();
    final StatSet currentStats = player.getEffectiveStats();
    if (enemyStats.getHitpoints() >= currentStats.getHitpoints()) {
        hitpointsReward++;
    }
    if (enemyStats.getAttack() >= currentStats.getAttack()) {
        attackReward++;
    }
    if (enemyStats.getDefense() >= currentStats.getDefense()) {
        defenseReward++;
    }

    final MutableStatSet trainedStats = player.getTrainedStats();
    trainedStats.increaseHitpoints(hitpointsReward);
    trainedStats.increaseAttack(attackReward);
    trainedStats.increaseDefense(defenseReward);
}

लेकिन वे सिर्फ लड़ाई के बाद नहीं बढ़े हैं। कुछ वस्तुओं का उपयोग करना, कुछ युक्तियों को नियोजित करना, युद्धक्षेत्र का चतुर उपयोग सभी अलग अनुभव प्रदान कर सकते हैं।

अब मेरे सवालों के लिए:

  1. क्या एक्सेसर्स और म्यूटेटर्स द्वारा अलग-अलग इंटरफेस में विभाजन के लिए एक नाम है?
  2. क्या इस तरह से उन्हें विभाजित करना 'सही' दृष्टिकोण है यदि वे समान रूप से उपयोग किए जाने की संभावना रखते हैं, या क्या एक अलग, अधिक स्वीकृत पैटर्न है जिसे मुझे इसके बजाय उपयोग करना चाहिए (उदाहरण के लिए Foo foo = FooFactory.createImmutableFoo();जो रिटर्न दे सकता है DefaultFooया DefaultMutableFooछिपा हुआ है क्योंकि createImmutableFooरिटर्न Foo)?
  3. क्या इस पैटर्न का उपयोग करने के लिए कोई तुरंत पूर्वाभास हो सकता है, इंटरफ़ेस पदानुक्रम को जटिल करने के लिए बचा सकता है?

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

EffectiveStatSetहम किसी भी तरह से कार्यक्षमता का विस्तार नहीं कर रहे हैं, क्योंकि इसके लिए एक नया वर्ग बनाना बहुत मायने नहीं रखता है। हम कार्यान्वयन को बदल सकते हैं, और EffectiveStatSetदो अलग-अलग का एक संयोजन बना सकते हैं StatSets, लेकिन मुझे लगता है कि यह सही समाधान नहीं है;

public class EffectiveStatSet implements StatSet {

    public EffectiveStatSet(StatSet baseStats, StatSet trainedStats) {
        // ...
    }

    public int getHitpoints() {
        return baseStats.getHitpoints() + (trainedStats.getHitpoints() / 4);
    }
}


1
मुझे लगता है कि समस्या आपकी वस्तु है, भले ही आप इसे मेरे 'अपरिवर्तनीय' इंटरफ़ेस तक पहुँचा रहे हों। Player.TrainStats ()
इवान

@gnat आपके पास कोई संदर्भ है जहां मैं उसके बारे में अधिक जान सकता हूं? संपादित प्रश्न के आधार पर, मुझे यकीन नहीं है कि मैं कैसे या जहां मैं इसे लागू कर सकता हूं।
ज़ीमस

@gnat: आपके लिंक (और इसके दूसरे-डिग्री और तीसरे-डिग्री लिंक) बहुत उपयोगी हैं, लेकिन ज्ञान के आकर्षक वाक्यांशों से बहुत कम मदद मिलती है। यह केवल गलतफहमी और निराशा को आकर्षित करता है।
rwong

जवाबों:


6

मेरे लिए ऐसा लगता है कि आपके पास एक समस्या की तलाश है।

क्या एक्सेसर्स और म्यूटेटर्स द्वारा अलग-अलग इंटरफेस में विभाजन के लिए एक नाम है?

यह थोड़ा उत्तेजक हो सकता है, लेकिन वास्तव में मैं इसे "चीजों को ओवरडिज़ाइन करना" या "चीजों को ओवरकॉम्प्लिकेट करना" कहूंगा। एक ही वर्ग के एक परिवर्तनशील और एक अपरिवर्तनीय संस्करण की पेशकश करके, आप एक ही समस्या के लिए दो कार्यात्मक समकक्ष समाधान प्रदान करते हैं, जो केवल प्रदर्शन के व्यवहार, एपीआई और साइड इफेक्ट के खिलाफ सुरक्षा जैसे गैर-कार्यात्मक पहलुओं में भिन्न होते हैं। मुझे लगता है कि ऐसा इसलिए है क्योंकि आप एक निर्णय लेने से डरते हैं जिसे कोई पसंद करता है, या क्योंकि आप C # में C ++ की "कॉन्स्ट" सुविधा को लागू करने का प्रयास करते हैं। मुझे लगता है कि 99% सभी मामलों में यह एक बड़ा अंतर नहीं होगा यदि उपयोगकर्ता उत्परिवर्तनीय या अपरिवर्तनीय संस्करण को चुनता है, तो वह अपनी समस्याओं को हल कर सकता है। इस प्रकार "उपयोग किए जाने वाले वर्ग की संभावना"

अपवाद तब होता है जब आप एक नई प्रोग्रामिंग भाषा या एक बहुउद्देश्यीय रूपरेखा तैयार करते हैं जो कुछ दस हजारों प्रोग्रामर या अधिक द्वारा उपयोग की जाने वाली होती है। तब यह वास्तव में बेहतर हो सकता है जब आप सामान्य प्रयोजन डेटा प्रकारों के अपरिवर्तनीय और परिवर्तनशील वेरिएंट पेश करते हैं। लेकिन यह एक ऐसी स्थिति है जहां आपके पास हजारों अलग-अलग उपयोग परिदृश्य होंगे - जो शायद आपके सामने आने वाली समस्या नहीं है, मुझे लगता है?

यदि वे समान रूप से उपयोग किए जाने की संभावना रखते हैं या एक अलग, अधिक स्वीकृत पैटर्न है, तो उन्हें इस तरह से विभाजित करना 'सही' दृष्टिकोण है

"अधिक स्वीकार्य पैटर्न" KISS कहा जाता है - यह सरल और बेवकूफ रहते हैं। अपनी लाइब्रेरी में विशिष्ट वर्ग / इंटरफ़ेस के लिए परिवर्तनशीलता के खिलाफ या उसके खिलाफ निर्णय लें। उदाहरण के लिए, यदि आपके "स्टेटसेट" में एक दर्जन विशेषताएँ या अधिक हैं, और वे ज्यादातर व्यक्तिगत रूप से बदले गए हैं, तो मैं परिवर्तनशील संस्करण को पसंद करूंगा और बस उन आधार आँकड़ों को संशोधित नहीं करूँगा जहाँ उन्हें संशोधित नहीं किया जाना चाहिए। Fooएक्स, वाई, जेड (एक तीन आयामी वेक्टर) के साथ एक वर्ग की तरह कुछ के लिए , मैं शायद अपरिवर्तनीय संस्करण को पसंद करूंगा।

क्या इस पैटर्न का उपयोग करने के लिए कोई तुरंत पूर्वाभास हो सकता है, इंटरफ़ेस पदानुक्रम को जटिल करने के लिए बचा सकता है?

Overcomplicated डिजाइन सॉफ्टवेयर कठिन परीक्षण करने के लिए, बनाए रखने के लिए कठिन, विकसित करने के लिए कठिन है।


1
मुझे लगता है कि आप मतलब है "KISS - यह इतना सरल रखें, बेवकूफ"
Epicblood

2

क्या एक्सेसर्स और म्यूटेटर्स द्वारा अलग-अलग इंटरफेस में विभाजन के लिए एक नाम है?

इसके लिए एक नाम हो सकता है यदि यह पृथक्करण उपयोगी है और एक लाभ प्रदान करता है जिसे मैं नहीं देखता । यदि अलगाववादियों को कोई लाभ नहीं मिलता है तो अन्य दो सवालों का कोई मतलब नहीं है।

क्या आप हमें कोई व्यावसायिक उपयोग-मामला बता सकते हैं, जहां दो अलग-अलग इंटरफेसेस हमें लाभ प्रदान करते हैं या यह प्रश्न एक अकादमिक समस्या है (YAGNI)?

मैं एक उत्परिवर्ती गाड़ी के साथ खरीदारी करने के बारे में सोच सकता हूं (आप अधिक लेख डाल सकते हैं) जो एक ऐसा आदेश बन सकता है जहां लेख को ग्राहक द्वारा किसी भी अधिक बदल सकते हैं। आदेश-स्थिति अभी भी परिवर्तनशील है।

कार्यान्वयन जो मैंने देखा है वे इंटरफेस को अलग नहीं करते हैं

  • जावा में कोई इंटरफ़ेस नहीं है ReadOnlyList

ReadOnly संस्करण "WritableInterface" का उपयोग करता है और एक अपवाद को फेंकता है यदि कोई लेखन विधि uesed है


मैंने प्राथमिक उपयोग-मामले की व्याख्या करने के लिए ओपी को संशोधित किया है।
झिमस

2
"जावा में कोई इंटरफ़ेस नहीं है ReadOnlyList" - स्पष्ट रूप से, होना चाहिए। यदि आपके पास एक कोड का एक टुकड़ा है जो एक सूची के रूप में एक सूची <T> को स्वीकार करता है, तो आप आसानी से नहीं बता सकते हैं कि क्या यह एक असम्बद्ध सूची के साथ काम करेगा। कोड जो सूची देता है, यह जानने का कोई तरीका नहीं है कि क्या आप उन्हें सुरक्षित रूप से संशोधित कर सकते हैं। एकमात्र विकल्प या तो संभावित रूप से अपूर्ण या गलत दस्तावेज पर निर्भर है, या केवल मामले में एक रक्षात्मक प्रतिलिपि बना रहा है। केवल संग्रह प्रकार को पढ़ने से यह बहुत सरल हो जाएगा।
जूल्स

@ जूल्स: वास्तव में, जावा तरीका सभी के ऊपर लगता है: यह सुनिश्चित करने के लिए कि प्रलेखन पूर्ण और सटीक है, साथ ही साथ केवल मामले में एक रक्षात्मक प्रतिलिपि बनाने के लिए। यह निश्चित रूप से बहुत बड़ी उद्यमी परियोजनाओं को मापता है।
5

1

एक परिवर्तनशील संग्रह इंटरफ़ेस और एक रीड-ओनली-कॉन्ट्रैक्ट कलेक्शन इंटरफ़ेस का पृथक्करण इंटरफ़ेस अलगाव सिद्धांत का एक उदाहरण है। मुझे नहीं लगता कि सिद्धांत के प्रत्येक अनुप्रयोग के लिए कोई विशेष नाम दिया गया है।

कुछ शब्दों को यहाँ देखें: "केवल पढ़ने के लिए अनुबंध" और "संग्रह"।

रीड-ओनली-कॉन्ट्रैक्ट का मतलब है कि क्लास क्लास Aको Bकेवल पढ़ने के लिए एक्सेस देता है, लेकिन इसका मतलब यह नहीं है कि अंतर्निहित संग्रह ऑब्जेक्ट वास्तव में अपरिवर्तनीय है। अपरिवर्तनीय का अर्थ है कि यह भविष्य में कभी नहीं बदल जाएगा, किसी भी एजेंट द्वारा कोई फर्क नहीं पड़ता। एक रीड-ओनली-कॉन्ट्रैक्ट केवल यह कहता है कि प्राप्तकर्ता को इसे बदलने की अनुमति नहीं है; किसी और (विशेष रूप से, वर्ग A) को इसे बदलने की अनुमति है।

किसी वस्तु को अपरिवर्तनीय बनाने के लिए, यह वास्तव में अपरिवर्तनीय होना चाहिए - एजेंट द्वारा अनुरोध किए बिना उसके डेटा को बदलने के प्रयासों से इनकार करना होगा।

पैटर्न उन वस्तुओं पर सबसे अधिक संभावना है जो डेटा के संग्रह का प्रतिनिधित्व करता है - सूचियां, अनुक्रम, फाइलें (स्ट्रीम), आदि।


शब्द "अपरिवर्तनीय" सनक बन जाता है, लेकिन अवधारणा नई नहीं है। और अपरिवर्तनीयता का उपयोग करने के कई तरीके हैं, साथ ही साथ कुछ और (यानी इसके प्रतियोगियों) का उपयोग करके बेहतर डिजाइन प्राप्त करने के कई तरीके हैं।


यहाँ मेरा दृष्टिकोण है (अपरिवर्तनीयता पर आधारित नहीं)।

  1. एक डीटीओ (डेटा ट्रांसफर ऑब्जेक्ट) को परिभाषित करें, जिसे मूल्य ट्यूपल के रूप में भी जाना जाता है।
    • यह डीटीओ तीन क्षेत्रों में शामिल होंगे: hitpoints, attack, defense
    • बस क्षेत्र: जनता, कोई भी लिख सकता है, कोई सुरक्षा नहीं।
    • हालाँकि, एक DTO को एक थकाऊ वस्तु होना चाहिए: यदि वर्ग Aको DTO को कक्षा में उत्तीर्ण करने की आवश्यकता होती है B, तो वह इसकी एक प्रतिलिपि बनाता है और इसके बजाय प्रतिलिपि पास करता है। इसलिए, Bडीटीओ का उपयोग कर सकते हैं, हालांकि यह उस पर पसंद (लिखने के लिए), डीटीओ को प्रभावित किए बिना, जो इसे Aरखता है।
  2. grantExperienceदो में टूटने का कार्य:
    • calculateNewStats
    • increaseStats
  3. calculateNewStats दो डीटीओ से इनपुट्स लेंगे, एक खिलाड़ी के आंकड़ों का प्रतिनिधित्व करने वाला और दूसरा दुश्मन के आंकड़ों का प्रतिनिधित्व करने वाला और गणना करने का।
    • इनपुट के लिए, कॉलर को आपकी आवश्यकताओं के अनुसार आधार, प्रशिक्षित या प्रभावी आंकड़ों में से एक का चयन करना चाहिए।
    • परिणाम एक नया डीटीओ जहां प्रत्येक क्षेत्र (होगा hitpoints, attack, defense) भंडार राशि बढ़ा दी करने के लिए है कि क्षमता के लिए।
    • डीटीओ को नई "राशि बढ़ाने के लिए" उन मूल्यों के लिए ऊपरी सीमा (लगाए गए अधिकतम कैप) के बारे में चिंता नहीं करता है।
  4. increaseStats खिलाड़ी पर एक विधि है (डीटीओ पर नहीं) जो डीटीओ को "वृद्धि करने के लिए" राशि लेता है, और उस डीटीओ पर उस वेतन वृद्धि को लागू करता है जो खिलाड़ी के स्वामित्व में है और खिलाड़ी के प्रशिक्षित डीटीओ का प्रतिनिधित्व करता है।
    • यदि इन आँकड़ों के लिए अधिकतम मूल्य लागू हैं, तो उन्हें यहाँ लागू किया जाता है।

यदि calculateNewStatsकिसी अन्य खिलाड़ी या दुश्मन की जानकारी (दो इनपुट डीटीओ में मूल्यों से परे) पर निर्भर नहीं पाया जाता है, तो यह विधि संभवतः परियोजना में कहीं भी स्थित हो सकती है।

यदि calculateNewStatsखिलाड़ी और शत्रु वस्तुओं पर पूर्ण निर्भरता पाई जाती है (अर्थात, भविष्य के खिलाड़ी और शत्रु वस्तुओं में नए गुण हो सकते हैं, और calculateNewStatsजितना संभव हो सके उनके नए गुणों का अधिक से अधिक उपभोग करने के लिए अद्यतन किया जाना चाहिए), तो calculateNewStatsउन दोनों को स्वीकार करना चाहिए वस्तुएं, केवल डीटीओ नहीं। हालाँकि, इसका गणना परिणाम अभी भी वृद्धि डीटीओ, या जो कुछ भी सरल डेटा-ट्रांसफर ऑब्जेक्ट हैं, जो एक वृद्धि / अपग्रेड करने के लिए उपयोग की जाने वाली जानकारी को वहन करता है।


1

यहां एक बड़ी समस्या है: सिर्फ इसलिए कि एक डेटा संरचना अपरिवर्तनीय है इसका मतलब यह नहीं है कि हमें इसके संशोधित संस्करणों की आवश्यकता नहीं हैवास्तविक डेटा संरचना के अपरिवर्तनीय संस्करण प्रदान करता है setX, setYऔर setZतरीकों - वे सिर्फ एक वापसी नई संरचना के बजाय वस्तु आप उन पर कहा जाता है को संशोधित करने की।

// Mutates mutableFoo
mutableFoo.setX(...)
// Creates a new updated immutableFoo, existing immutableFoo is unchanged
newFoo = immutableFoo.setX(...)

तो आप अपने सिस्टम के एक हिस्से को अन्य भागों को प्रतिबंधित करते हुए इसे बदलने की क्षमता कैसे देते हैं? एक परिवर्तनशील वस्तु के साथ अपरिवर्तनीय संरचना के उदाहरण के संदर्भ में। मूल रूप से, आपके खिलाड़ी वर्ग के बजाय उसके आँकड़े ऑब्जेक्ट को म्यूट करने में सक्षम होते हैं, जबकि हर दूसरे वर्ग को उसके आँकड़ों के बारे में अपरिवर्तनीय दृश्य देते हैं, उसके आँकड़े अपरिवर्तनीय होते हैं और खिलाड़ी उत्परिवर्तनीय होता है। के बजाय:

// Stats are mutable, mutates self.stats
self.stats.setX(...)

आपके पास होगा:

// Stats are immutable, mutates self, setX() returns new updated stats
self.stats = self.stats.setX(...)

फर्क देखें? सांख्यिकी ऑब्जेक्ट पूरी तरह से अपरिवर्तनीय है, लेकिन खिलाड़ी का वर्तमान आँकड़े अपरिवर्तनीय वस्तु का एक परस्पर संदर्भ है। दो इंटरफेस बनाने की कोई आवश्यकता नहीं है - बस डेटा संरचना को पूरी तरह से अपरिवर्तनीय बना दें और एक परस्पर संदर्भ को प्रबंधित करें जहां आप ऐसा करते हैं कि आप इसे स्टोर करने के लिए उपयोग कर रहे हैं।

इसका मतलब यह है कि आपके सिस्टम की अन्य वस्तुएं आंकड़े ऑब्जेक्ट के संदर्भ पर भरोसा नहीं कर सकती हैं - खिलाड़ी द्वारा अपने आंकड़ों को अपडेट करने के बाद खिलाड़ी के पास जो ऑब्जेक्ट हैं, वे आंकड़े ऑब्जेक्ट नहीं होंगे।

यह वैसे भी अधिक समझ में आता है, क्योंकि वैचारिक रूप से यह वास्तव में आँकड़े नहीं हैं जो बदल रहे हैं, यह खिलाड़ी के मौजूदा आँकड़े हैं । आँकड़े वस्तु नहीं। आँकड़ों का संदर्भ खिलाड़ी के ऑब्जेक्ट पर है। तो आपके सिस्टम के अन्य भाग उस संदर्भ के आधार पर, सभी को स्पष्ट रूप से संदर्भित करना चाहिए player.currentStats()या कुछ ऐसा होना चाहिए जो खिलाड़ी की अंतर्निहित आँकड़ों की वस्तु का एक हिस्सा पाने के बजाय, उसे कहीं और संग्रहीत करना और म्यूटेशन के माध्यम से अद्यतन करने पर निर्भर होना चाहिए।


1

वाह ... यह वास्तव में मुझे वापस ले जाता है। मैंने कुछ समय इसी विचार की कोशिश की। मैं इस पर ध्यान देने के लिए बहुत जिद्दी था क्योंकि मुझे लगता था कि सीखने के लिए कुछ अच्छा होगा। मैंने दूसरों को कोड में भी यह कोशिश करते देखा है। अधिकांश कार्यान्वयन जिन्हें मैंने पढ़ा है-केवल इंटरफेस जैसे कि आपका FooViewerया ReadOnlyFooराइट-ओनली इंटरफ़ेस, FooEditorया WriteableFooजावा में मुझे लगता है कि मैंने FooMutatorएक बार देखा है । मुझे यकीन नहीं है कि इस तरह से चीजें करने के लिए एक आधिकारिक या सामान्य शब्दावली भी है।

यह मेरे लिए उन जगहों के लिए कुछ भी उपयोगी नहीं था जो मैंने कोशिश की थी। मैं इससे पूरी तरह से बचूंगा। मैं ऐसा करूंगा जैसा कि अन्य लोग सुझाव दे रहे हैं और एक कदम पीछे ले जाएं और विचार करें कि क्या आपको वास्तव में अपने बड़े विचार में इस धारणा की आवश्यकता है। मुझे यकीन नहीं है कि ऐसा करने का एक सही तरीका है क्योंकि मैंने वास्तव में इस कोशिश के दौरान अपने द्वारा उत्पादित किसी भी कोड को कभी नहीं रखा। हर बार मैंने काफी प्रयास और सरलीकृत चीजों के बाद वापसी की। और कि मैं दूसरों YAGNI और चुंबन और सूखी के बारे में क्या कहा की तर्ज पर मतलब कुछ द्वारा।

एक संभव नकारात्मक पहलू: पुनरावृत्ति। आपको संभावित रूप से बहुत सी कक्षाओं के लिए ये इंटरफेस बनाने होंगे और यहां तक ​​कि सिर्फ एक वर्ग के लिए आपको प्रत्येक विधि का नाम देना होगा और प्रत्येक हस्ताक्षर का कम से कम दो बार वर्णन करना होगा। कोडिंग में मुझे जलाने वाली सभी चीजों में से, इस तरह से कई फाइलें बदलने से मुझे सबसे ज्यादा परेशानी होती है। मैं अंत में एक जगह या दूसरे में बदलाव करना भूल जाता हूं। एक बार आपके पास Foo नामक एक वर्ग है और FooViewer और FooEditor नामक इंटरफेस, अगर आप तय करते हैं तो बेहतर होगा कि आप इसे बार कहते हैं, इसके बजाय आपको रिफ्लेक्टर करना है-> तीन बार नाम बदलें जब तक कि आपके पास वास्तव में आश्चर्यजनक स्मार्ट आईडीई न हो। मुझे भी ऐसा लगा, जब मेरे पास कोड जनरेटर से आने वाले कोड की काफी मात्रा थी।

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

और फिर आपके द्वारा उल्लिखित जटिलता है। मुझे संदेह है कि मैं अपने कोड के साथ इस विशेष तरीके से कभी भी जाऊंगा। यहां तक ​​कि इस जगह के लिए कोड के लिए मेरी समग्र योजना में सबसे अच्छा फिट (एक ORM मैंने बनाया) मैंने इसे खींच लिया और इसे कोड करने के लिए कुछ आसान के साथ बदल दिया।

मैं वास्तव में आपके द्वारा बताई गई रचना पर अधिक विचार करूंगा। मैं उत्सुक हूं कि आपको क्यों लगता है कि यह एक बुरा विचार होगा। मैं होने की संभावना है | EffectiveStatsलिखें और अपरिवर्तनीय Statsऔर कुछ की तरह StatModifiersहै, जो आगे के कुछ सेट रचना होगा StatModifierकि प्रतिनिधित्व करते हैं जो कुछ (कुछ वृद्धि क्षेत्र, थकान में अस्थायी प्रभाव, आइटम, स्थान) आँकड़े को संशोधित सकता है, लेकिन है कि आपकी EffectiveStatsवजह से समझने की जरूरत है नहीं होगा StatModifiersचाहेंगे प्रबंधित करें कि वे चीजें क्या थीं और कितने प्रभाव में थीं और किस तरह के आंकड़े हैं। StatModifierअलग-अलग चीजों के लिए एक इंटरफ़ेस होगा और "आई एम इन द ज़ोन", "जब दवाई बंद हो जाए" जैसी चीजों को जान सकता है, आदि ... लेकिन किसी भी अन्य ऑब्जेक्ट को ऐसी चीजों को जानने की अनुमति भी नहीं देनी होगी। केवल यह कहना होगा कि यह किस स्टेट और कैसे संशोधित हुआ। बेहतर अभी तक StatModifierबस Statsदूसरे के आधार पर एक नई अपरिवर्तनीय उत्पादन के लिए एक विधि को उजागर कर सकता है Statsजो अलग होगा क्योंकि इसे उचित रूप से बदल दिया गया था। आप तब कुछ कर सकते थे currentStats = statModifier2.modify(statModifier1.modify(baseStats))और सभी Statsअपरिवर्तनीय हो सकते थे। मैं यह भी कोड नहीं करता कि सीधे, मैं शायद सभी संशोधक के माध्यम से लूप करूंगा और प्रत्येक के साथ शुरू होने वाले पिछले संशोधक के परिणाम पर लागू होगा baseStats

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.