जावा स्विंग में व्यू / कंट्रोलर से मॉडल को पूरी तरह से डिकम्पोज कैसे करें


10

क्या जावा स्विंग ऐप में मॉडल कक्षाओं को व्यू / कंट्रोलर कक्षाओं से अलग करने के लिए आमतौर पर सहमत-डिज़ाइन डिज़ाइन दिशानिर्देशों का एक संग्रह है? मैं इतना चिंतित नहीं हूं कि व्यू / कंट्रोलर को मॉडल के बारे में कुछ भी पता नहीं है जैसे कि अन्य तरीके से: मैं अपने मॉडल को डिज़ाइन करना चाहता हूं, जिसमें javax.swing में किसी भी चीज़ का कोई ज्ञान नहीं है। आदर्श रूप से इसमें एक साधारण एपीआई होना चाहिए जो इसे सीएलआई के रूप में आदिम के रूप में संचालित करने में सक्षम हो। यह होना चाहिए, शिथिल बोल, एक "इंजन।"

मॉडल में GUI घटनाओं का संचार करना बहुत कठिन नहीं है - एक्शन कलाकार मॉडल के एपीआई को कॉल कर सकते हैं। लेकिन जब मॉडल अपना स्वयं का राज्य परिवर्तन करता है तो जीयूआई को वापस प्रतिबिंबित करने की क्या आवश्यकता है? यही "सुनना" है, लेकिन यहां तक ​​कि "सुनी जाने वाली" पूरी तरह से निष्क्रिय नहीं है; इसके लिए आवश्यक है कि मॉडल को श्रोता को जोड़ने के बारे में पता हो।

विशेष समस्या जो मुझे सोच रही थी उसमें फ़ाइलों की एक कतार शामिल है। जीयूआई पक्ष में एक के DefaultListModelपीछे एक है JList, और फ़ाइल सिस्टम से फ़ाइलों को चुनने और उन्हें जेएलस्ट में जोड़ने के लिए कुछ जीयूआई सामान है। मॉडल की तरफ, यह इस "कतार" (जेएलस्ट से गायब होने के कारण) के नीचे से फाइलों को खींचना चाहता है और उन्हें किसी तरह से संसाधित करता है। वास्तव में, मॉडल कोड पहले से ही लिखा गया है - यह वर्तमान में ArrayList<File>एक सार्वजनिक add(File)पद्धति को बनाए रखता है और उजागर करता है । लेकिन मैं एक नुकसान में हूं कि कैसे अपने मॉडल को कुछ भारी, स्विंग-विशिष्ट संशोधनों के बिना दृश्य / नियंत्रक के साथ काम करना है।

मैं जावा और जीयूआई प्रोग्रामिंग दोनों के लिए बहुत नया हूं, हमेशा "बैच" और "बैक-एंड" प्रोग्रामिंग अब तक कर चुका हूं - इसलिए मॉडल और यूआई के बीच एक सख्त विभाजन बनाए रखने में मेरी रुचि है, अगर यह संभव है और यदि यह हो सकता है पढ़ाया गया।



Btw: एमवीसी में मॉडल को डिफ़ॉल्ट रूप से व्यू और कंट्रोलर से डिकॉय किया जाना चाहिए। आपको अपनी पाठ्यपुस्तक को फिर से पढ़ना चाहिए, मुझे लगता है कि आपने अवधारणा को नहीं समझा है। और आप एक कस्टम संग्रह को कार्यान्वित कर सकते हैं, जो तब बदलता है, जब वह बदल जाता है। बहुत कुछ .NET का INotifyCollectionChanged इंटरफ़ेस।
फाल्कन

@ फाल्कन: लिंक के लिए धन्यवाद। मुझे यकीन नहीं है कि मैं आपकी टिप्पणी को समझता हूं, लेकिन "मॉडल को डिफ़ॉल्ट रूप से दृश्य और नियंत्रक से हटा दिया जाना चाहिए"। आप rephrase या विस्तृत कर सकते हैं?
चाप

जवाबों:


10

एमवीसी के लिए आमतौर पर सहमत-ऑन (यानी डिफैक्टो ) डिजाइन दिशानिर्देश नहीं हैं। ऐसा नहीं है कि यह पूरी तरह से स्वयं करना कठिन है, लेकिन आपको अपनी कक्षाओं और बहुत समय और धैर्य पर कुछ योजना बनाने की आवश्यकता है।

इसका कोई निश्चित समाधान नहीं है क्योंकि एमवीसी करने के कई तरीके हैं, सभी अपने पेशेवरों और विपक्षों के साथ। तो बस इसके बारे में होशियार रहें और वही करें जो आपको सबसे अच्छा लगे।

अपने प्रश्न का उत्तर देने के लिए, आप वास्तव में नियंत्रक को दृश्य से अलग करना चाहते हैं (इसलिए आप स्विंग ऐप और कंसोल ऐप दोनों के लिए समान व्यापार नियम तर्क का उपयोग कर सकते हैं)। स्विंग के उदाहरण में आप स्विंग में JWindowऔर जो भी विजेट से नियंत्रक को हटाना चाहते हैं । जिस तरह से मैं करता था (वास्तविक रूपरेखाओं का उपयोग करने से पहले) नियंत्रक के उपयोग के लिए एक इंटरफ़ेस बनाना है:

public interface PersonView {
    void setPersons(Collection<Person> persons);
}

public class PersonController {

    private PersonView view;
    private PersonModel model;

    public PersonController(PersonView view, PersonModel model) {
        this.view = view;
        this.model = model;
    }
    // ... methods to affect the model etc. 
    // such as refreshing and sort:

    public void refresh() {
        this.view.setPersons(model.getAsList());
    }

    public void sortByName(boolean descending) {
       // do your sorting through the model.
       this.view.setPersons(model.getSortedByName());
    }

}

स्टार्टअप के दौरान इस समाधान के लिए आपको नियंत्रक को दृश्य में पंजीकृत करना होगा।

public class PersonWindow extends JWindow implements PersonView {

    PersonController controller;
    Model model;

    // ... Constructor etc.

    public void initialize() {
        this.controller = new PersonController(this, this.model);

        // do all the other swing stuff

        this.controller.refresh();
    }

    public void setPersons(Collection<Person> persons) {
        // TODO: set the JList (in case that's you are using) 
        // to use the given parameter
    }

}

इसके बजाय आपके लिए सभी सेटअप करने के लिए IoC- कंटेनर बनाना एक अच्छा विचार हो सकता है।

किसी भी तरह, आप एक ही नियंत्रक का उपयोग करके, केवल-कंसोल दृश्य को लागू कर सकते हैं:

public class PersonConsole implements PersonView {

    PersonController controller;
    Model model;

    public static void main(String[] args) {
        new PersonConsole().run();
    }

    public void run() {
        this.model = createModel();
        this.controller = new PersonController(this, this.model);

        this.controller.refresh();
    }

    public void setPersons(Collection<Person> persons) {
        // just output the collection to the console

        StringBuffer output = new StringBuffer();
        for(Person p : persons) {
            output.append(String.format("%s%n", p.getName()));
        }

        System.out.println(output);
    }

    public void createModel() {
        // TODO: create this.model
    }

    // this could be expanded with simple console menu with keyboard
    // input and other console specific stuff

}    

मजेदार हिस्सा यह है कि इवेंट हैंडलिंग कैसे की जाती है। मैंने इसे इंटरफ़ेस के उपयोग से कंट्रोलर को स्वयं रजिस्टर करने की अनुमति देकर इसे लागू किया है, यह ऑब्जर्वर पैटर्न का उपयोग करके किया जाता है (यदि आप .NET का उपयोग कर रहे हैं तो आप इवेंट हैंडलर का उपयोग कर रहे हैं)। यहां एक सरल "दस्तावेज़ पर्यवेक्षक" का एक उदाहरण दिया गया है, वह संकेत जब कोई दस्तावेज़ सहेजा या लोड किया गया हो।

public interface DocumentObserver {
    void onDocumentSave(DocModel saved);
    void onDocumentLoad(DocModel loaded);
}

// in your controller you implement register/unregister methods
private List<DocumentObserver> observers;

// register observer in to the controller
public void addObserver(DocumentObserver o) {
    this.observers.add(o);
}

// unregisters observer from the controller
public void removeObserver(DocumentObserver o) {
    this.observers.remove(o);
}

public saveDoc() {
    DocModel model = model.save();
    for (DocumentObserver o : observers) {
        o.onDocumentSave(model);
    }
}

public loadDoc(String path) {
    DocModel model = model.load(path);
    for (DocumentObserver o : observers) {
        o.onDocumentLoad(model);
    }        
}

इस तरह, दस्तावेज़ के अद्यतनों की सदस्यता लेने के बाद से दृश्य स्वयं को ठीक से अपडेट कर सकता है। DocumentObserverइंटरफ़ेस को लागू करने के लिए यह सब करना है :

public class DocumentWindow extends JWindow 
        implements DocView, DocumentObserver {

    //... all swing stuff

    public void onDocumentSave(DocModel saved) {
        // No-op
    }

    public void onDocumentLoad(DocModel loaded) {
        // do what you need with the loaded model to the
        // swing components, or let the controller do it on
        // the view interface
    }

    // ...

}

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

एक जोड़ी है जिसे मैं अपने सिर से सोच सकता हूं: ग्रहण और नेटबीन्स आरसीपी।

आपको अभी भी अपने लिए नियंत्रक और मॉडल विकसित करने की आवश्यकता है, लेकिन इसीलिए आप ORM का उपयोग करते हैं। उदाहरण हाइबरनेट होगा ।

IoC कंटेनर सभी अच्छे हैं, लेकिन इसके लिए रूपरेखा भी हैं। जैसे कि स्प्रिंग (जो अन्य चीजों के साथ-साथ डेटा हैंडलिंग भी करता है)।


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

0

इस पर मेरा मानना ​​है कि कभी-कभी हमें समझौता करने की जरूरत होती है

जैसा कि आप कहते हैं, यह बहुत अच्छा होगा यदि हम इसके लिए स्पष्ट बुनियादी ढांचे के बिना देखे गए ऑब्जेक्ट के बिना निहित अधिसूचना को बदल सकते हैं। जावा, C #, C ++ जैसी आम अनिवार्य भाषाओं के लिए, उनकी रनटाइम वास्तुकला बहुत हल्की है, वैसे भी, अब भी। इसके द्वारा मेरा मतलब है कि यह इस समय भाषा विनिर्देश का हिस्सा नहीं है।

आपके विशेष मामले में, मुझे नहीं लगता कि INOTifyPropertyChanged (जैसा कि c #) में कुछ सामान्य इंटरफ़ेस को परिभाषित करना / उपयोग करना वास्तव में एक बुरी बात है , क्योंकि यह स्वचालित रूप से किसी भी दृष्टिकोण से युग्मित नहीं है - यह सिर्फ यह कहता है कि यदि आप इसे बदलते हैं मैं आपको बताऊंगा

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


और मैं इसके बारे में सोचो, मैं तुम्हें रहे हों तो सही एहसास - मॉडल वस्तु है करने के लिए शामिल होने के कुछ जीयूआई कि एक परिवर्तन हुआ है करने के लिए अधिसूचना शुरू करने में हद; अन्यथा GUI को परिवर्तनों की खोज के लिए मॉडल को परागित करना होगा - और यह बुरा है।
Chap
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.