Magento 2: एक व्यावहारिक कक्षा क्या है?


17

तो, मुझे पता है कि मैजेंटो 2 में एक प्रॉक्सी क्लास क्या है। मैंने इसके बारे में भयानक एलन स्टॉर्म लेख पढ़ा है और मैं पूरी तरह से समझता हूं कि उन कक्षाओं को कैसे उत्पन्न किया जाता है।

हालांकि, और मुझे नहीं पता कि यह इसलिए है क्योंकि मैं एक गैर देशी अंग्रेजी वक्ता हूं या अगर एलन के स्पष्टीकरण में गैर मूल कक्षाएं हैं जो बहुत सार हैं, लेकिन मुझे यह समझने में कठिन समय हो रहा है कि यह कैसे काम करता है और विशेष रूप से उपयोग करने के समय यह विकास के दौरान।

तो आइए इस उदाहरण को मूल से लेते हैं app/code/Magento/GoogleAdwords/etc/di.xml:

<?xml version="1.0"?>
<!--
/**
 * Copyright © 2016 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\GoogleAdwords\Observer\SetConversionValueObserver">
        <arguments>
            <argument name="collection" xsi:type="object">Magento\Sales\Model\ResourceModel\Order\Collection\Proxy</argument>
        </arguments>
    </type>
</config>

मैं जानना चाहता हूँ:

  • उस विशेष मामले में एक प्रॉक्सी क्लास का उपयोग क्यों किया जाता है?
  • जब सामान्य तौर पर, किसी को प्रॉक्सी क्लास का उपयोग करना चाहिए?

जवाबों:


18

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

प्रॉक्सी क्लास का उपयोग केवल तब किया जाना चाहिए जब आप उस वस्तु के निर्माण के दौरान एक महंगे ऑपरेशन को अंजाम देते हैं। एक अच्छा उदाहरण है सिम्फनी कंसोल कमांड्स:

कल्पना करें कि आपका कंसोल कमांड निर्भरता के रूप में ProductRepository का उपयोग कर रहा है। उत्पाद रिपॉजिटरी निर्माणकर्ता कैटलॉग डेटाबेस में MySQL कनेक्शन स्थापित करता है।

इसका मतलब है कि हर bin/magentoकॉल पर, चाहे आप जिस भी कमांड को अंजाम दें, रिपॉजिटरी की निर्भरता तुरंत हो जाएगी। तो इससे बचने का एकमात्र तरीका एक प्रॉक्सी बनाकर मूल वस्तु के आलसी तात्कालिकता का उपयोग करना है। इस मामले में डेटाबेस, कैटलॉग डेटाबेस से कनेक्शन केवल तभी स्थापित किया जाएगा जब आप एक रिपॉजिटरी विधि कहते हैं।

आशा है कि प्रॉक्सी के विचार को बेहतर ढंग से समझने में मदद मिलेगी।


1
तथ्य यह है कि मैंने जो उदाहरण चुना वह बेकार है और मुझे और भी भ्रमित कर दिया। फिर से मैं अवधारणा को समझता हूं। लेकिन मुझे क्या नहीं मिलता है: यदि आप इसे हर कमांड के लिए उपयोग नहीं करते हैं, तो आप ProductRepository को कंसोल कमांड पर निर्भरता के रूप में क्यों जोड़ेंगे। क्या यह केवल आपके द्वारा उपयोग किए जाने वाले आदेशों के लिए निर्भरता नहीं होनी चाहिए? आपने जो कहा उसके अनुसार, प्रॉक्सी एक निर्भरता को "स्किप" करने का एक तरीका है? लेकिन उस मामले में, यह पहली जगह में एक निर्भरता क्यों है?
राफेल

1
मुझे लगता है कि सिम्फनी कंसोल कमांड एक बढ़िया उदाहरण है, जैसा कि आपको मैगेंटो से बात करनी चाहिए, और ऐसा करने का एकमात्र तरीका कंस्ट्रक्टर में एक निर्भरता को निर्दिष्ट करना है। Symfony कंसोल घटक में आपको हर एक कमांड के लिए एक क्लास बनाना होगा। इस वर्ग में तरीकों को कॉन्फ़िगर और निष्पादित करना है। कॉन्फ़िगर करें इसका नाम और तर्क सेट करता है, जबकि निष्पादित वास्तव में महंगा ऑपरेशन निष्पादित कर रहा है। यदि महंगी कार्रवाई को कॉन्फ़िगर पर निष्पादित किया जाता है, तो जितना आप खराब कर रहे हैं, यही कारण है कि प्रॉक्सी इस समस्या का जवाब है।
इवान चेपर्नी

13

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

यदि आप एक प्रॉक्सी पर नजर डालते हैं \Magento\Framework\View\Layout\Proxy, तो Magento ने जनरेट किया है, जैसे , आप देखेंगे कि इसमें मूल कक्षा के समान ही सभी विधियाँ हैं। अंतर यह है कि हर बार जब भी किसी को बुलाया जाता है, तो यह जांचता है कि क्या यह जिस वर्ग का छद्म है वह वास्तव में तात्कालिक है, और यदि नहीं तो वस्तु बनाता है। (यह एक _getSubject()या _getCache()विधि में होता है ।)

यह निर्भरता इंजेक्शन के लिए आलसी लोड हो रहा है।

यदि वर्ग निर्भरता का उपयोग हमेशा आपकी कक्षा द्वारा नहीं किया जाता है, तो आपको एक प्रॉक्सी का उपयोग करना चाहिए और:

  • अपनी खुद की बहुत अधिक निर्भरता है, या
  • इसके निर्माता में संसाधन-गहन कोड शामिल हैं, या
  • इसे इंजेक्ट करने से साइड इफेक्ट होते हैं

इसका एक अच्छा उदाहरण सत्र है। ObjectManager के माध्यम से सत्र प्राप्त करना बुरा अभ्यास है, लेकिन सत्र वर्ग की तरह इंजेक्शन लगाने से \Magento\Customer\Model\Sessionचीजें टूट सकती हैं यदि आपकी कक्षा कभी भी उस सत्र के दायरे से बाहर चलती है (जैसे कि आप किसी व्यवस्थापक पृष्ठ पर दृश्य ग्राहक सत्र को इंजेक्ट करते हैं)। आप \Magento\Customer\Model\Session\Proxyइसके बजाय सत्र के प्रॉक्सी को इंजेक्ट करके प्राप्त करते हैं, और जब आप जानते हैं कि यह मान्य है तो केवल इसका संदर्भ दें। जब तक आप इसका संदर्भ नहीं देते हैं, सत्र को कभी भी त्वरित नहीं किया जाता है, और कुछ भी नहीं टूटता है।

आपके विशिष्ट उदाहरण में di.xml, ऐसा लगता है कि उन्होंने उस नियंत्रक के कारखाने के बजाय एक नियंत्रक को सही ठहराने के लिए प्रॉक्सी का उपयोग किया। किसी भी तरह से, यह नहीं है कि क्या proxies के लिए इस्तेमाल किया जा करने का इरादा कर रहे हैं, और उस स्थिति में इसका लाभ न्यूनतम होने की संभावना है।


7

Magento 2 प्रकार की ऑटोजेनरेटेड प्रॉक्सी का उपयोग डिज़ाइन गलतियों को "ठीक" करने के लिए किया जा सकता है। यह बहुत आसान हो सकता है। 2 उपयोग मामले हैं:

  1. एक महंगी वस्तु ग्राफ को लपेटें जो कि हर बार आश्रित को नहीं चाहिए।

  2. एक चक्रीय निर्भरता को तोड़ें जहाँ वर्ग Aनिर्भर करता है Bऔर वर्ग Bनिर्भर करता है A
    इंजेक्ट B\Proxyकरने Aसे आपको तुरंत मदद मिलती है A, जो तब बदले में तुरंत इस्तेमाल किया जा सकता है Bजब वास्तव में इसका उपयोग वास्तविक Aवस्तु के साथ किया जाता है ।

के मामले में 1. निर्भरता है कि हमेशा के लिए इस्तेमाल नहीं एक संकेत है कि dependee वर्ग ज्यादा करने के लिए करता है, या हो सकता है एक विधि से ज्यादा के लिए करता है। कंसोल कमांड @ivan का उल्लेख इसका एक अच्छा उदाहरण है।

2 के मामले में मुझे उस निर्भरता को तोड़ने का एक सामान्य तरीका नहीं पता है। अगर समय है तो मैं फिर से लिखता हूं, लेकिन यह एक विकल्प नहीं हो सकता है।

एक साइड नोट के रूप में, मैं यह जोड़ना चाहूंगा कि ओओपी में ऑटोगेन्जेनेटेड आलसी इंस्टेंटेशन एक मैगेंटो 2 का उपयोग करता है (जैसे रिमोट प्रॉक्सी) की तुलना में कई अधिक प्रकार के परदे के पीछे हैं।


हैलो @ विनै, __constructor () विधि या di.xml के माध्यम से प्रॉक्सी कक्षाओं का उपयोग करने का तरीका क्या है?
अंकोला

1
मैगेंटो कोडिंग दिशानिर्देशों के अनुसार खंड 2.5 समर्थक वर्ग के निर्माणकर्ताओं में घोषित नहीं होने चाहिए। प्रॉक्सी को di.xml में घोषित किया जाना चाहिए। Devdocs.magento.com/guides/v2.3/coding-standards/…
Vinai

1

यहाँ उत्तर हैं

उस विशेष मामले में एक प्रॉक्सी क्लास का उपयोग क्यों किया जाता है?

यदि आप कोड के नीचे एक नज़दीकी नज़र रखते हैं, जो कि क्लास के लिए लिखा गया है "SetConversionValueObserver", अगर Google adwards सक्रिय नहीं है "वापसी" और अगर कोई आदेश नहीं है "वापसी"। मतलब, ऑर्डर कलेक्शन ऑब्जेक्ट केवल तब बनाया जाएगा जब ऑर्डर आईड्स मौजूद हों और Google ऐडवर्ड्स सक्रिय हो। यदि हम वास्तविक ऑर्डर कलेक्शन क्लास को इंजेक्ट करते हैं, तो ऑब्जेक्ट मैनेजर Google ऐडवर्ड्स को सक्रिय किए बिना अपने मूल वर्ग ऑब्जेक्ट्स के साथ संग्रह ऑब्जेक्ट बनाता है जो कि सक्रिय नहीं है और ऑर्डर सफलता पृष्ठ को धीमा कर देता है। इसलिए, मांग पर बेहतर वस्तु बनाएं जो प्रॉक्सी का उपयोग हो। /vendor/magento/module-google-adwords/Observer/SetConversionValueObserver.php

 /**
 * Set base grand total of order to registry
 *
 * @param \Magento\Framework\Event\Observer $observer
 * @return \Magento\GoogleAdwords\Observer\SetConversionValueObserver
 */
public function execute(\Magento\Framework\Event\Observer $observer)
{
    if (!($this->_helper->isGoogleAdwordsActive() && $this->_helper->isDynamicConversionValue())) {
        return $this;
    }
    $orderIds = $observer->getEvent()->getOrderIds();
    if (!$orderIds || !is_array($orderIds)) {
        return $this;
    }
    $this->_collection->addFieldToFilter('entity_id', ['in' => $orderIds]);
    $conversionValue = 0;
    /** @var $order \Magento\Sales\Model\Order */
    foreach ($this->_collection as $order) {
        $conversionValue += $order->getBaseGrandTotal();
    }
    $this->_registry->register(
        \Magento\GoogleAdwords\Helper\Data::CONVERSION_VALUE_REGISTRY_NAME,
        $conversionValue
    );
    return $this;
}

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

वास्तविक लेआउट निर्माता बनाम लेआउट / प्रॉक्सी

public function __construct(
    Layout\ProcessorFactory $processorFactory,
    ManagerInterface $eventManager,
    Layout\Data\Structure $structure,
    MessageManagerInterface $messageManager,
    Design\Theme\ResolverInterface $themeResolver,
    Layout\ReaderPool $readerPool,
    Layout\GeneratorPool $generatorPool,
    FrontendInterface $cache,
    Layout\Reader\ContextFactory $readerContextFactory,
    Layout\Generator\ContextFactory $generatorContextFactory,
    AppState $appState,
    Logger $logger,
    $cacheable = true,
    SerializerInterface $serializer = null
) {
    $this->_elementClass = \Magento\Framework\View\Layout\Element::class;
    $this->_renderingOutput = new \Magento\Framework\DataObject();
    $this->serializer = $serializer ?: ObjectManager::getInstance()->get(SerializerInterface::class);

    $this->_processorFactory = $processorFactory;
    $this->_eventManager = $eventManager;
    $this->structure = $structure;
    $this->messageManager = $messageManager;
    $this->themeResolver = $themeResolver;
    $this->readerPool = $readerPool;
    $this->generatorPool = $generatorPool;
    $this->cacheable = $cacheable;
    $this->cache = $cache;
    $this->readerContextFactory = $readerContextFactory;
    $this->generatorContextFactory = $generatorContextFactory;
    $this->appState = $appState;
    $this->logger = $logger;
}

प्रॉक्सी कंस्ट्रक्टर, एक नज़र डालें, कोई भी पैरेंट कंस्ट्रक्टर नहीं जिसे केवल लेआउट क्लास का नाम दिया गया हो ताकि वास्तविक ऑब्जेक्ट क्रिएशन तब हो जब उसे कॉल किया जाता है।

 /**
 * Proxy constructor
 *
 * @param \Magento\Framework\ObjectManagerInterface $objectManager
 * @param string $instanceName
 * @param bool $shared
 */
public function __construct(
    \Magento\Framework\ObjectManagerInterface $objectManager,
    $instanceName = \Magento\Framework\View\Layout::class,
    $shared = true
) {
    $this->_objectManager = $objectManager;
    $this->_instanceName = $instanceName;
    $this->_isShared = $shared;
}

प्रॉक्सी क्लास में डिमांड पर ऑब्जेक्ट बनाने की विधि है, _subject पास क्लास की ऑब्जेक्ट है।

/**
 * Get proxied instance
 *
 * @return \Magento\Framework\View\Layout
 */
protected function _getSubject()
{
    if (!$this->_subject) {
        $this->_subject = true === $this->_isShared
            ? $this->_objectManager->get($this->_instanceName)
            : $this->_objectManager->create($this->_instanceName);
    }
    return $this->_subject;
}

और विधि _subject का उपयोग करके कहा जाता है।

/**
 * {@inheritdoc}
 */
public function setGeneratorPool(\Magento\Framework\View\Layout\GeneratorPool $generatorPool)
{
    return $this->_getSubject()->setGeneratorPool($generatorPool);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.