क्या पर्यवेक्षक पैटर्न उपयुक्त है जब पर्यवेक्षक एक दूसरे से स्वतंत्र नहीं हैं?


9

मेरे पास class Car2 गुण हैं: int priceऔर boolean inStock। यह भी एक धारण Listकी abstract class State(खाली वर्ग)। 2 राज्य हैं जिन्हें कार पर लागू किया जा सकता है और प्रत्येक को अपनी स्वयं की कक्षा द्वारा दर्शाया गया है: class Upgrade extends Stateऔर class Shipping extends State

A Carप्रत्येक 2 राज्यों में से किसी भी संख्या को पकड़ सकता है। राज्यों के निम्नलिखित नियम हैं:

  • Upgrade: 1प्रत्येक राज्य के लिए कार के लिए लागू मूल्य के बाद खुद को कहते हैं।
  • Shipping: यदि Shippingसूची में कम से कम 1 राज्य है, तो इसके inStockलिए सेट है false

उदाहरण के लिए, के साथ शुरू price = 1और inStock = true:

add Shipping s1    --> price: 1, inStock: false
add Upgrade g1     --> price: 1, inStock: false
add Shipping s2    --> price: 2, inStock: false
add Shipping s3    --> price: 3, inStock: false
remove Shipping s2 --> price: 2, inStock: false
remove Upgrade g1  --> price: 1, inStock: false
remove Shipping s1 --> price: 1, inStock: false
remove Shipping s3 --> price: 1, inStock: true

मैं ऑब्जर्वर पैटर्न के बारे में सोच रहा था, जहां प्रत्येक ऑपरेशन पर्यवेक्षकों को जोड़ता और हटाता था। मेरे मन में कुछ ऐसा था, लेकिन यह उन नियमों का पालन नहीं करता जो मैंने किए थे:

abstract class State implements Observer {

    public abstract void update();
}

class Car extends Observable {

    List<State> states = new ArrayList<>();
    int price = 100;
    boolean inStock = true;

    void addState(State state) {

        if (states.add(state)) {
            addObserver(state);
            setChanged();
            notifyObservers();
        }
    }

    void removeState(State state) {

        if (states.remove(state)) {
            deleteObserver(state);
            setChanged();
            notifyObservers();
        }
    }
}

class Upgrade extends State {

    @Override
    public void update(Observable o, Object arg) {

        Car c = (Car) o;
        int bonus = c.states.size() - c.states.indexOf(this) - 1;
        c.price += bonus;
        System.out.println(c.inStock + " " + c.price);
    }
}

class Shipping extends State {

    @Override
    public void update(Observable o, Object arg) {

        Car c = (Car) o;
        c.inStock = false;
        System.out.println(c.inStock + " " + c.price);
    }
}

जाहिर है, यह काम नहीं करता है। जब एक Shippingहटा दिया जाता है, तो कुछ को यह जांचना पड़ता है कि क्या inStockझूठे के लिए एक और राज्य सेटिंग है, इसलिए एक निष्कासन Shippingबस नहीं हो सकता है inStock = true। प्रत्येक कॉल पर Upgradeबढ़ता है price। मैंने तब डिफ़ॉल्ट मानों के लिए स्थिरांक जोड़े और उन पर आधारित पुनर्गणना का प्रयास किया।

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

  1. चूंकि प्रत्येक पर्यवेक्षक प्राप्त करता है Car, यह वर्तमान में पंजीकृत सभी अन्य पर्यवेक्षकों को देख सकता है और उसी के आधार पर परिवर्तन कर सकता है। मुझे नहीं पता कि क्या इस तरह से पर्यवेक्षकों को उलझाना समझदारी है।
  2. जब एक पर्यवेक्षक जोड़ा जाता है या अंदर हटा दिया जाता है Car, तो एक पुनर्गणना होगी। हालाँकि, इस पुनर्गणना को सभी पर्यवेक्षकों पर ध्यान दिए बिना करना होगा जो अभी जोड़ा / हटाया गया था।
  3. एक बाहरी "प्रबंधक" वर्ग है जो जोड़ने और हटाने के तरीकों को बुलाएगा और पुनर्गणना करेगा।

वर्णित व्यवहार को लागू करने के लिए एक अच्छा डिजाइन पैटर्न क्या है और यह कैसे काम करेगा?


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

यदि आप इसे हाथ से कर रहे हैं तो आप समस्या का समाधान कैसे करेंगे?
जेम्स यंगमैन

@JamesYoungman मैंने अपने 3 विकल्प - एक बाहरी प्रबंधक का उपयोग करके समाप्त किया। इस मामले के लिए आपके द्वारा कागज पर लिखे गए नियम सरल हैं, लेकिन भाषा जो विकल्प आपको उन्हें लागू करने के लिए देती है, वे इस मामले में सीमित हैं । इसलिए एक डिजाइन पैटर्न की आवश्यकता है। "स्पष्ट रूप से आप इसे कैसे करेंगे" के बारे में सोचकर नियमों के स्पष्ट सेट को लागू करने की तुलना में एल्गोरिदम के लिए अधिक काम करता है।
14:

@ user1803551 आपने अच्छा चुना।
ट्यूलेंस कोर्डोवा

सभी घटनाओं के लिए एक ईवेंट हैंडलर रखें। यह हैंडलर केवल वस्तु की पूर्ण स्थिति की पुन: गणना के लिए प्रवेश बिंदु है। यह एक पुरातात्विक समस्या है। जब आप "शीर्ष से नीचे, बाएं से दाएं" के रूप में काम करते हुए इसे प्रकट करते हैं - सब कुछ ए-ओके है, लेकिन फिर बीच में कुछ बदलने से ठीक से पुनर्गणना नहीं होती है। यदि आप कभी भी पूछते हैं कि "मैं ईवेंट हैंडलिंग ऑर्डर की गारंटी कैसे दे सकता हूं?", अब आप जानते हैं कि आपको क्या करना है।
राडारोब

जवाबों:


1

यदि आप सिस्टम को अलग तरीके से देखते हैं तो पर्यवेक्षक बहुत अच्छा काम करेंगे। खुद को पर्यवेक्षक बनाने के लिए राज्यों के बजाय, आप "राज्य परिवर्तन पर्यवेक्षक" बनने के लिए 2 नई कक्षाएं बना सकते हैं: एक पर्यवेक्षक "मूल्य" को अपडेट करेगा, दूसरा एक "इनस्टॉक" अपडेट करेगा। इस तरह वे स्वतंत्र होंगे यदि आपके पास इनस्टॉक या इसके विपरीत मूल्य के लिए नियम नहीं हैं, यानी यदि सबकुछ राज्य परिवर्तनों को देखते हुए गणना की जा सकती है। इस तकनीक को "इवेंट सोर्सिंग" कहा जाता है (उदाहरण के लिए देखें - https://ookami86.github.io/event-sourcing-in-ults/ )। यह प्रोग्रामिंग में एक पैटर्न है जिसमें कुछ उल्लेखनीय अनुप्रयोग हैं।

एक अधिक सामान्य प्रश्न का उत्तर देते हुए, कभी-कभी आपके पास पर्यवेक्षकों के बीच वास्तव में निर्भरता होती है। उदाहरण के लिए, आप एक पर्यवेक्षक को दूसरे से पहले प्रतिक्रिया करने के लिए चाहते हो सकता है। ऐसे मामले में आमतौर पर आदेश देने या निर्भरता से निपटने के लिए ऑब्जर्वेबल क्लास का कस्टम कार्यान्वयन करना संभव है।


0

मैंने विकल्प 3 के साथ जाना समाप्त कर दिया - एक बाहरी प्रबंधक का उपयोग करना। प्रबंधक जोड़ने और हटाने के लिए जिम्मेदार है Stateसे रों Carरों और पर्यवेक्षकों द्वारा सूचना ये परिवर्तन होने के लिए।

यहां बताया गया है कि मैंने कोड को कैसे संशोधित किया। मैं हटा दिया Observable/ Observerक्योंकि मैं अपने खुद के कार्यान्वयन कर रहा हूँ JDK की।

प्रत्येक इसके लागू होने का Stateसंदर्भ रखता Carहै।

abstract class State {

    Car car;

    State(Card car) { this.car = car; }

    public abstract void update();
}

class Upgrade extends State {

    @Override
    public void update() {

        int bonus = car.states.size() - car.states.indexOf(this) - 1;
        car.price += bonus;
        System.out.println(car.inStock + " " + car.price);
    }
}

class Shipping extends State {

    @Override
    public void update() {

        car.inStock = false;
        System.out.println(car.inStock + " " + car.price);
    }
}

Carकेवल अपनी स्थिति रखता है (भ्रम से बचने के लिए: गुण) और Stateएस को जोड़ने और हटाने का काम नहीं करता है :

class Car extends Observable {

    List<State> states = new ArrayList<>();
    int price = 100;
    boolean inStock = true;
}

यहाँ प्रबंधक है। यह Carअपने State(पर्यवेक्षकों) के प्रबंधन के काम (अवलोकन) से आगे निकल गया है ।

class StatesManager {

    public void addState(Card car, State state) {

        car.states.add(state);
        for (State state : car. states)
            state.update;
    }

    public void removeState(Card car, State state) {

        car.states.remove(state);
        for (State state : car. states)
            state.update;
    }
}

ध्यान रखने योग्य कुछ बातें:

  • सभी पर्यवेक्षकों को हर बदलाव के बारे में सूचित किया जाता है। एक अधिक चतुर घटना वितरण योजना पर्यवेक्षकों की updateपद्धति में अनावश्यक कॉल को समाप्त कर सकती है ।
  • पर्यवेक्षक विभिन्न अवसरों के लिए अधिक "अपडेट" जैसी विधियों को उजागर करना चाह सकते हैं। एक उदाहरण के रूप में, वे वर्तमान updateपद्धति को विभाजित कर सकते हैं updateOnAddऔर updateOnRemoveयदि वे इन परिवर्तनों में से केवल एक में रुचि रखते हैं। तब addStateऔर removeStateतरीकों को तदनुसार अपडेट किया जाएगा। पिछले बिंदु के साथ यह दृष्टिकोण एक मजबूत, एक्स्टेंसिबल और लचीले तंत्र के रूप में समाप्त हो सकता है।
  • मैंने यह निर्दिष्ट नहीं किया Stateकि एस जोड़ने और हटाने का निर्देश क्या देता है और जब ऐसा होता है तो यह प्रश्न के लिए महत्वपूर्ण नहीं है। हालांकि, इस उत्तर के मामले में, विचार करने के लिए निम्नलिखित बिंदु है। चूंकि Stateअब Carप्रबंधक के तरीके को कॉल करने से पहले इसके (कोई खाली निर्माणकर्ता नहीं उजागर) के साथ बनाया जाना चाहिए , addStateऔर removeStateविधियों को इसे लेने की आवश्यकता नहीं है Carऔर बस इसे पढ़ सकते हैं state.car
  • डिफ़ॉल्ट रूप से अवलोकन योग्य पर पंजीकरण के क्रम में पर्यवेक्षकों को सूचित किया जाता है। एक अलग आदेश निर्दिष्ट किया जा सकता है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.