इस लेख में, मैं अंतर्निहित GWT MVP फ्रेमवर्क के मुख्य बिंदुओं को उजागर करने का प्रयास करूंगा। एक उदाहरण के रूप में, इस दृष्टिकोण का उपयोग करके बनाया गया एक छोटा अनुप्रयोग उपयोग किया जाएगा।
यह लेख एक निःशुल्क पथ ( GWT MVP विकास ) है और यह किसी भी तरह से अद्वितीय होने का दिखावा नहीं करता है। अगर किसी को इस तरह के एक बड़े परिचय में दिलचस्पी थी
मैं तुरंत कहूंगा कि मैं एमवीपी डिजाइन पैटर्न पर ही ध्यान केंद्रित नहीं करूंगा। आप अपने आप को इसकी योजना से परिचित कर सकते हैं, उदाहरण के लिए, ( एमवीपी विकी पर )। % उपयोगकर्ता नाम% ब्याज के लिए, मैं उस एप्लिकेशन का स्क्रीनशॉट दूंगा जिसे मैंने समाप्त किया था।
हां, मैं समझता हूं कि एप्लिकेशन कुछ भी उपयोगी नहीं है, लेकिन इसके आधार पर मैं वास्तुकला को अलग-अलग स्वतंत्र भागों (मेल, संपर्क और कार्य, जिस तरह से, बस छत से लिया गया है) में विभाजित करने का तरीका दिखाने की कोशिश करूंगा, उनके बीच स्विचिंग और संचार व्यवस्थित करें। GWT 2.1 में निर्मित तंत्र का उपयोग करना। इसके अलावा, एमवीपी पैटर्न का एम-घटक, अर्थात्। मॉडल, क्योंकि उदाहरण के प्रयोजनों के लिए आवेदन में कोई डेटा बाइंडिंग नहीं है।
एंबेडेड एमवीपी की मुख्य विशेषताएं
जीवीटी टीम ने एमवीपी का उपयोग करते हुए एक एप्लिकेशन के निर्माण के लिए निम्नलिखित प्रमुख घटकों का प्रस्ताव दिया:
- गतिविधि - शास्त्रीय दृष्टिकोण में, यह प्रस्तुतकर्ता है। वर्तमान में खुले दृश्य के तर्क के लिए जिम्मेदार। इसमें कोई GWT विजेट या UI-संबंधित कोड नहीं है। लेकिन बदले में, यह एक संबद्ध दृश्य वस्तु (दृश्य) है। गतिविधि प्रबंधक का उपयोग करके स्वचालित रूप से प्रारंभ और बंद हो जाता है
- एक्टिविटी मैनजर एक बिल्ट-इन ऑब्जेक्ट है जो इसमें पंजीकृत होने वाली गतिविधियों के जीवन चक्र को नियंत्रित करता है।
- स्थान - वर्तमान दृश्य की स्थिति के लिए जिम्मेदार। मूल रूप से, URL का उपयोग करके दृश्य की स्थिति प्रसारित की जाती है (उदाहरण के लिए, ID = <so-> संपादन के लिए) या किसी अन्य तरीके से, इतिहास टोकन के साथ एक संपर्क खोलें। PlaceHistoryHandler ऑब्जेक्ट के लिए धन्यवाद, जो ब्राउज़र के एड्रेस बार में परिवर्तन के लिए "सुनता है", प्लेस ऑब्जेक्ट की वांछित स्थिति को फिर से बनाया जा सकता है। किसी प्लेस ऑब्जेक्ट की स्थिति को फिर से संगठित या सहेजते समय, प्लेसटॉकेनाइज़र ऑब्जेक्ट का उपयोग किया जाता है, जिसमें वर्णित ऑब्जेक्ट की स्थिति को फिर से संगठित और सहेजते समय तरीकों को कहा जाता है।
- PlaceHistoryMapper, ActivityMapper - मैपर क्लासेस, जो सभी प्लेस और एक्टिविटीज़ के एप्लिकेशन को रजिस्टर करने के लिए अनिवार्य रूप से जिम्मेदार हैं। पास प्लेस प्लेस ऑब्जेक्ट (जो बदले में इतिहास टोकन से फिर से बनाया गया था) के आधार पर एक्टिविटी मेपर भी तय करता है कि कौन सी एक्टिविटी ऑब्जेक्ट संबंधित URL स्थिति से संबद्ध होगी
- दृश्य - सरल समग्र विजेट जो अन्य नेस्टेड विजेट से मिलकर बना सकते हैं। उनमें एक जुड़े प्रस्तोता (गतिविधि) का एक उदाहरण है। यूआई की ज़रूरतों के लिए तर्क के अलावा उनके पास तर्क नहीं हैं, उदाहरण के लिए, शैली स्विच करना, आदि। सभी उपयोगी तर्क का निष्पादन दृश्य संबंधित प्रस्तुतकर्ता को उसके तरीकों को कॉल करके दर्शाता है।
आइए अब हम एक उदाहरण के रूप में वास्तविक जीवन कोड का उपयोग करते हुए व्यक्तिगत रूप से इन सभी घटकों पर अधिक विस्तार से विचार करें। वैसे, एप्लिकेशन कोड मुफ्त पहुंच के लिए उपलब्ध है। इसलिए आप इसे पढ़ते हुए देख सकते हैं।
दृश्य घटक या दृश्य
सबसे पहले, यह कहने योग्य है कि एमवीपी में यह प्रस्तोता और देखने के बीच केवल "विनिमय" करने के लिए प्रथागत है। इसलिए, अनुप्रयोग में प्रत्येक दृश्य के लिए एक संबंधित इंटरफ़ेस है
package com.gshocklab.mvp.client.mvp.view; import com.google.gwt.user.client.ui.IsWidget; public interface IMailView extends IsWidget { public void setPresenter(IMailPresenter presenter); public interface IMailPresenter { } }
दृश्य का इंटरफ़ेस प्रस्तुतकर्ता के संगत इंटरफ़ेस का वर्णन करता है, जो सभी पेलोड (डेटा के लिए अनुरोध भेजना, घटना बस से प्रसंस्करण की घटनाओं आदि) का प्रदर्शन करेगा।
इस इंटरफ़ेस का कार्यान्वयन सरल होगा और इसमें कोई विशेष समस्या नहीं होनी चाहिए।
public class MailView extends Composite implements IMailView { interface MailViewUiBinder extends UiBinder<Widget, MailView> { } private static MailViewUiBinder uiBinder = GWT.create(MailViewUiBinder.class); private IMailPresenter presenter; public MailView() { initWidget(uiBinder.createAndBindUi(this)); } @Override public void setPresenter(IMailPresenter presenter) { this.presenter = presenter; } }
लिंक की गई ui.xml फ़ाइल में केवल एक विजेट है, सादे पाठ के साथ लेबल। उसका कोड लाने का कोई मतलब नहीं है; आप इसे परियोजना की वेबसाइट पर देख सकते हैं।
यह सब देखने के लिए है। अब हम गतिविधि के लिए और अधिक दिलचस्प हो जाते हैं।
पृष्ठों (दृश्य) या गतिविधि का तर्क
बाईं ओर डेमो एप्लिकेशन में लिंक के साथ एक नेविगेशन बार है। जब आप इन लिंक पर क्लिक करते हैं, तो आप विचारों के बीच स्विच करते हैं और वर्तमान लिंक के लिए CSS शैली सेट करते हैं। मैंने अमूर्त अभिभावक वर्ग AbstractMainActivity के लिए यह कार्रवाई की, जो अंतर्निहित वर्ग योग्यता के वंशज है
package com.gshocklab.mvp.client.mvp.activity; public abstract class AbstractMainActivity extends AbstractActivity { private static Map<String, Element> navLinks = new LinkedHashMap<String, Element>(); static { navLinks.put(AppConstants.MAIL_LINK_ID, DOM.getElementById(AppConstants.MAIL_LINK_ID)); navLinks.put(AppConstants.CONTACTS_LINK_ID, DOM.getElementById(AppConstants.CONTACTS_LINK_ID)); navLinks.put(AppConstants.TASKS_LINK_ID, DOM.getElementById(AppConstants.TASKS_LINK_ID)); } public void applyCurrentLinkStyle(String viewId) { for (String linkId : navLinks.keySet()) { final Element link = navLinks.get(linkId); if (link == null) continue; if (linkId.equals(viewId)) { link.addClassName("b-current"); } else { link.removeClassName("b-current"); } } } }
और एक विशिष्ट गतिविधि का एक विशिष्ट कार्यान्वयन
package com.gshocklab.mvp.client.mvp.activity; public class MailActivity extends AbstractMainActivity implements IMailView.IMailPresenter { private ClientFactory clientFactory; public MailActivity(ClientFactory clientFactory) { this.clientFactory = clientFactory; } @Override public void start(AcceptsOneWidget container, EventBus eventBus) { applyCurrentLinkStyle(AppConstants.MAIL_LINK_ID); final IMailView view = clientFactory.getMailView(); view.setPresenter(this); container.setWidget(view.asWidget()); } }
यह कैसे काम करता है: जब एक एक्टिविटी मैनजर को PlaceHistoryManager से URL परिवर्तन घटना प्राप्त होती है, तो यह एक्टिविटीमैपर का उपयोग करके वांछित गतिविधि उदाहरण बनाता है और इसे स्टार्ट () विधि का उपयोग करके शुरू करता है। इस पद्धति का एक पैरामीटर कंटेनर है जिसमें दृश्य विजेट प्रतिस्थापित किया जाएगा। हमें क्लायंटफैक्टरी से दृश्य मिलता है, जो थोड़ा कम होगा। हम प्रस्तुतकर्ता को प्राप्त दृश्य उदाहरण में इंजेक्ट करते हैं और दृश्य को विजेट के रूप में प्रदर्शित करते हैं। हां, लिंक के लिए एक सीएसएस नियम भी निर्धारित किया गया है, जो वर्तमान दृश्य की ओर जाता है। लेकिन यह विशुद्ध रूप से दृश्य डिजाइन है।
ClientFactory एक सरल कारखाना है जो सही ऑब्जेक्ट बनाता है। इसका इंटरफ़ेस निम्नानुसार बताया गया है
public interface ClientFactory { public EventBus getEventBus(); public PlaceController getPlaceController(); public IMailView getMailView(); public IContactsView getContactsView(); public ITasksView getTasksView(); }
इसका कार्यान्वयन "बुद्धि और त्वरित बुद्धि" में भिन्न नहीं होता है
public class ClientFactoryImpl implements ClientFactory { private final EventBus eventBus = new SimpleEventBus(); private final PlaceController placeController = new PlaceController(eventBus); private final IMailView mailView = new MailView(); private final IContactsView contactsView = new ContactsView(); private final ITasksView tasksView = new TasksView(); @Override public EventBus getEventBus() { return eventBus; } @Override public PlaceController getPlaceController() { return placeController; } @Override public IMailView getMailView() { return mailView; } @Override public IContactsView getContactsView() { return contactsView; } @Override public ITasksView getTasksView() { return tasksView;} }
GWT मॉड्यूल की विवरण फ़ाइल में वर्णित नियम के अनुसार क्लाइंटफ़ैक्टिव ऑब्जेक्ट की तात्कालिकता को Deffered बाइंडिंग का उपयोग करके किया जाएगा। लेकिन इस बारे में अधिक बाद में फिर से अनुभाग में, जो एकल कार्य प्रणाली में संपूर्ण एमवीपी-अर्थव्यवस्था के विन्यास पर चर्चा करेगा। यह ध्यान देने योग्य है कि क्लाइंटफैक्टिव हल करने वाले कार्यों के लिए वास्तविक परियोजनाओं में, Google GIN का उपयोग करना बेहतर है। डीआई उपकरण के फायदे का वर्णन करने में कोई समझदारी नहीं है, वे पहले से ही समझने योग्य हैं।
एम्बेडेड एमवीपी के प्रमुख तत्वों में से एक ऐसा ऑब्जेक्ट है जो UI की स्थिति के लिए जिम्मेदार है और इतिहास टोकन में हेरफेर करता है।
जगह या हैश urls और उनके प्रसंस्करण
जैसा कि ऊपर बताया गया है, UI की वर्तमान स्थिति के लिए प्लेस ऑब्जेक्ट जिम्मेदार है। स्थिति इतिहास टोकन के माध्यम से URL से गुजरती है। वास्तव में, इस ऑब्जेक्ट में आप उन मापदंडों को संग्रहीत कर सकते हैं जो एक हैश URL के साथ प्रेषित होते हैं। टोकनर ऑब्जेक्ट का उपयोग करके URL की स्थिति एन्कोडेड / डीकोड की गई है। जब हैश URL में प्रेषित अनुरोध पैरामीटर के साथ काम करते हैं, तो निम्न नियम का पालन करना बहुत महत्वपूर्ण है: सभी पैरामीटर जो प्रसंस्करण के बाद हमें URL से "दर्ज" करते हैं, उन्हें वापस उसी रूप में URL में एन्कोड किया जाना चाहिए। यह तर्क है जो टोकनाइज़र वर्ग के तरीकों में लागू किया गया है।
समझौते के द्वारा, जिसे जीडब्ल्यूटी टीम द्वारा स्वीकार किया जाता है और आधिकारिक मैनुअल में वर्णित किया जाता है, टोकन धारक वर्ग को आमतौर पर प्लेस ऑब्जेक्ट के आंतरिक स्थिर वर्ग के रूप में वर्णित किया जाता है। यह प्लेस ऑब्जेक्ट के चर में क्वेरी मापदंडों को संग्रहीत करने के लिए कोड को सरल करता है। यद्यपि आप टोकन के लिए अलग-अलग कक्षाओं के साथ दृष्टिकोण को लागू कर सकते हैं।
आदेश निराधार नहीं होने के लिए, MailPlace वर्ग के कोड पर विचार करें
package com.gshocklab.mvp.client.mvp.place; import com.google.gwt.place.shared.Place; import com.google.gwt.place.shared.PlaceTokenizer; import com.google.gwt.place.shared.Prefix; public class MailPlace extends Place { private static final String VIEW_HISTORY_TOKEN = "mail"; public MailPlace() { } @Prefix(value = VIEW_HISTORY_TOKEN) public static class Tokenizer implements PlaceTokenizer<MailPlace> { @Override public MailPlace getPlace(String token) { return new MailPlace(); } @Override public String getToken(MailPlace place) { return ""; } } }
यह वर्ग अंतर्निहित स्थान वर्ग से विरासत में मिला है। इसमें हैश URL का हिस्सा स्थिर घोषित किया गया है, जो विशिष्ट रूप से राज्य की पहचान करेगा। इस मामले में, यह "मेल" है। टोकनिनेटर वर्ग राज्य के पुनर्निर्माण और इतिहास के टोकन के माध्यम से इसे बचाने के लिए जिम्मेदार है। एक विशिष्ट हैश यूआरएल के टोकन को बाइंडिंग प्रीफ़िक्स एनोटेशन का उपयोग करके किया जाता है।
प्रसंस्करण इतिहास आम तौर पर एक दिलचस्प विषय है और एक अलग लेख के हकदार हैं। यहां हम खुद को इस तथ्य तक सीमित रखते हैं कि हमारे पास प्रत्येक प्लेस ऑब्जेक्ट से जुड़ा एक अलग हैश URL होगा। यह URL ":" के साथ समाप्त होना चाहिए। इस बृहदान्त्र के बाद, आप अतिरिक्त पैरामीटर निर्दिष्ट कर सकते हैं, उदाहरण के लिए, आप फॉर्म का URL #mail: inbox, #contacts: new, आदि बना सकते हैं। और इन टोकन को गेटप्लस () विधि में संसाधित किया जाएगा। वास्तव में, हैश URL का पहला भाग सबसिस्टम आइडेंटिफ़ायर (मेल, कार्य इत्यादि) है, जो सब कुछ जो कोलन के बाद आता है उसे एक्शन सबसिस्टम माना जा सकता है।
डेमो प्रोजेक्ट में, अतिरिक्त टोकन (या क्रियाएं) का उपयोग नहीं किया जाता है, इसलिए getToken () विधि सभी टोकन में एक खाली स्ट्रिंग लौटाती है, और getPlace () विधि बनाई गई जगह ऑब्जेक्ट को वापस करती है।
वांछित गतिविधि का निर्धारण करना और संचालकों को पंजीकृत करना
जब कोई नया URL आता है और प्लेस ऑब्जेक्ट को तुरंत हटा दिया जाता है, तो एक्टिविज़न मैनेजर, ActivMapper का उपयोग करके, यह तय करता है कि कौन सा प्रस्तोता ऑब्जेक्ट चलाना है। इस परिभाषा को सरलता से लागू किया जाता है
public class DemoActivityMapper implements ActivityMapper { private ClientFactory clientFactory; public DemoActivityMapper(ClientFactory clientFactory) { super(); this.clientFactory = clientFactory; } @Override public Activity getActivity(Place place) { if (place instanceof MailPlace) { return new MailActivity(clientFactory); } else if (place instanceof ContactsPlace) { return new ContactsActivity(clientFactory); } else if (place instanceof TasksPlace) { return new TasksActivity(clientFactory); } return null; } }
रजिस्टर हैश URL हैंडलर्स, अर्थात Tokenizers इंटरफेस में चलते हैं PlaceHistoryMapper
package com.gshocklab.mvp.client.mvp; import com.google.gwt.place.shared.PlaceHistoryMapper; import com.google.gwt.place.shared.WithTokenizers; import com.gshocklab.mvp.client.mvp.place.ContactsPlace; import com.gshocklab.mvp.client.mvp.place.MailPlace; import com.gshocklab.mvp.client.mvp.place.TasksPlace; @WithTokenizers({MailPlace.Tokenizer.class, ContactsPlace.Tokenizer.class, TasksPlace.Tokenizer.class}) public interface DemoPlaceHistoryMapper extends PlaceHistoryMapper { }
इस स्तर पर सभी की जरूरत है कि बस @WithTokenizers एनोटेशन में आवेदन टोकन वर्गों को सूचीबद्ध करें।
यह सब एक साथ रखना
MVP फ्रेमवर्क मेकेनिज्म को शुरू करने और शुरू करने के लिए सभी कोड onModuleLoad () विधि EntryPoint में संकलित किए गए हैं
package com.gshocklab.mvp.client; import com.google.gwt.activity.shared.ActivityManager; import com.google.gwt.activity.shared.ActivityMapper; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.event.shared.EventBus; import com.google.gwt.place.shared.PlaceController; import com.google.gwt.place.shared.PlaceHistoryHandler; import com.google.gwt.user.client.History; import com.google.gwt.user.client.ui.RootLayoutPanel; import com.google.gwt.user.client.ui.SimplePanel; import com.gshocklab.mvp.client.layout.AppLayout; import com.gshocklab.mvp.client.mvp.DemoActivityMapper; import com.gshocklab.mvp.client.mvp.DemoPlaceHistoryMapper; import com.gshocklab.mvp.client.mvp.place.MailPlace; public class MvpInActionEntryPoint implements EntryPoint { private SimplePanel containerWidget; private MailPlace defaultPlace = new MailPlace(); @Override public void onModuleLoad() { final AppLayout mainLayout = new AppLayout(); containerWidget = mainLayout.getAppContentHolder(); final ClientFactory clientFactory = GWT.create(ClientFactory.class); EventBus eventBus = clientFactory.getEventBus(); PlaceController placeController = clientFactory.getPlaceController(); // activate activity manager and init display ActivityMapper activityMapper = new DemoActivityMapper(clientFactory); ActivityManager activityManager = new ActivityManager(activityMapper, eventBus); activityManager.setDisplay(containerWidget); // display default view with activated history processing DemoPlaceHistoryMapper historyMapper = GWT.create(DemoPlaceHistoryMapper.class); PlaceHistoryHandler historyHandler = new PlaceHistoryHandler(historyMapper); historyHandler.register(placeController, eventBus, defaultPlace); RootLayoutPanel.get().add(mainLayout); History.newItem("mail:"); } }
मुझे लगता है कि स्पष्टीकरण कोड द्वारा अतिरेक होगा, सब कुछ सरल और स्पष्ट है। यह ध्यान दिया जाना चाहिए कि History.newItem ("मेल:") पर एक कॉल सतही हो सकती है। MailActivity पहले से ही लॉन्च है, क्योंकि MailPlace को डिफॉल्ट प्लेस के रूप में निर्दिष्ट किया गया है। एक और बात यह है कि स्टार्टअप पर हम ब्राउज़र के एड्रेस बार में हैश URL # ईमेल नहीं देखेंगे। यदि किसी प्रोजेक्ट के लिए स्टार्ट हैश URL प्रदर्शित करना महत्वपूर्ण नहीं है, तो History.newItem () पर कॉल हटाया जा सकता है।
काम करने के लिए अंतर्निहित MVP- फ्रेमवर्क के लिए, आपको GWT- मॉड्यूल (gwt.xml- फ़ाइल) के विवरण फ़ाइल में संबंधित GWT- मॉड्यूल को जोड़ने की आवश्यकता है
<?xml version="1.0" encoding="UTF-8"?> <module rename-to='mvpinaction'> <inherits name='com.google.gwt.user.User' /> <inherits name="com.google.gwt.activity.Activity"/> <inherits name="com.google.gwt.place.Place"/> <entry-point class='com.gshocklab.mvp.client.MvpInActionEntryPoint' /> <replace-with class="com.gshocklab.mvp.client.ClientFactoryImpl"> <when-type-is class="com.gshocklab.mvp.client.ClientFactory" /> </replace-with> <source path='client' /> </module>
ClientFactory उदाहरण बनाने के लिए आस्थगित बाध्यकारी नियम भी यहाँ निर्दिष्ट किया गया है।
एक निष्कर्ष के बजाय
बस इतना ही। मैं AppLayout एप्लिकेशन के रूट लेआउट के साथ फ़ाइल प्रदान नहीं करता, आप इसे स्रोत में देख सकते हैं। इस फ़ाइल में लिंक हैं जिनकी href विशेषताओं में एप्लिकेशन सबसिस्टम में नेविगेट करने के लिए हैश URL हैं। आप ब्राउज़र के एड्रेस बार में सही URL टाइप करके भी एक या अन्य सबसिस्टम खोल सकते हैं। राज्य को URL से उपयुक्त स्थान पर परिवर्तित करने की प्रक्रिया को संबंधित गतिविधि के लॉन्च के साथ स्वचालित रूप से शुरू किया जाएगा, जो उस दृश्य को प्रदर्शित करेगा जिसकी आपको आवश्यकता है।
मैं इसके अलावा नोट करता हूं कि नोट और डेमो प्रोजेक्ट ने जीवन में ऐसे महत्वपूर्ण क्षणों को संबोधित नहीं किया जैसे कि इवेंट बस (इवेंटबस), हैश यूआरएल मापदंडों का प्रसंस्करण, और बहुत कुछ।
एक कार्यशील डेमो प्रोजेक्ट , Google कोड का स्रोत कोड । सावधानी बरतें!
प्रतिक्रिया और टिप्पणियों की प्रतीक्षा है।
बहु पत्र के लिए क्षमा करें। मुझे उम्मीद है कि यह परिचयात्मक नोट किसी के लिए उपयोगी साबित हुआ (हालांकि यह पूरी तरह से एकीकृत एमवीपी की पूरी शक्ति को कवर नहीं करता है), मैंने इसे एक कारण के लिए लिखा था और यह वास्तव में शांत GWT अनुप्रयोगों के कार्यान्वयन के लिए एक शुरुआती बिंदु के रूप में काम करेगा