PHP में कई वंशानुक्रम


97

मैं इस तथ्य के इर्द-गिर्द घूमने के लिए एक अच्छे, साफ रास्ते की तलाश कर रहा हूं कि PHP5 अभी भी एक से अधिक विरासत का समर्थन नहीं करता है। यहाँ वर्ग पदानुक्रम है:

संदेश
- TextMessage
-------- InvitationTextMessage
- EmailMessage
-------- आमंत्रणमेलमेलन

निमंत्रण * दो प्रकार के वर्गों में बहुत कुछ है; मैं एक आम अभिभावक वर्ग, निमंत्रण, कि वे दोनों से विरासत में मिला है प्यार करता हूँ। दुर्भाग्य से, उनके पास अपने वर्तमान पूर्वजों के साथ बहुत कुछ है ... TextMessage और EmailMessage। यहाँ कई विरासत के लिए शास्त्रीय इच्छा।

समस्या को हल करने के लिए सबसे हल्के वजन का दृष्टिकोण क्या है?

धन्यवाद!


4
ऐसे कई मामले नहीं हैं जिनमें विरासत (या यहां तक ​​कि कई विरासत) उचित है। SOLID सिद्धांतों को देखें। वंशानुक्रम पर रचना को प्राथमिकता दें।
ओन्दीजे मिर्तेज

2
@ Ond meanejMirtes आपका क्या मतलब है - "ऐसे कई मामले नहीं जिनमें विरासत जायज़ है?"
स्टाइलर

12
मेरा मतलब है - विरासत लाभ की तुलना में अधिक समस्याएं लाती है (लिस्कोव प्रतिस्थापन सिद्धांत को देखें)। आप रचना के साथ लगभग सब कुछ हल कर सकते हैं और बहुत सारे सिरदर्द बचा सकते हैं। वंशानुक्रम भी स्थिर है - इसका मतलब है कि आप वह नहीं बदल सकते जो कोड में पहले से लिखा गया है। लेकिन रचना का उपयोग रनटाइम पर किया जा सकता है और आप गतिशील रूप से कार्यान्वयन चुन सकते हैं - जैसे विभिन्न कैशिंग तंत्रों के साथ एक ही वर्ग का पुन: उपयोग।
ओन्दोज मिर्ट्स

5
PHP 5.4 में "लक्षण" हैं: stackoverflow.com/a/13966131/492130
f.ardelian

1
मैं सुझाव देना चाहूंगा कि शुरुआती लोग विरासत का उपयोग कभी न करें । सामान्य तौर पर, केवल दो स्थितियों में विरासत की अनुमति दी जाती है: 1) एक पुस्तकालय का निर्माण करते समय, इसलिए उपयोगकर्ता कम कोड लिखते हैं और 2) जब परियोजना का नेतृत्व मांग करता है तो आप इसका उपयोग करते हैं
gurghet

जवाबों:


141

एलेक्स, कई बार आपको कई विरासतों की आवश्यकता होती है एक संकेत है कि आपकी वस्तु संरचना कुछ गलत है। जिस स्थिति में आपने उल्लिखित किया है, मुझे लगता है कि आपके पास वर्ग जिम्मेदारी बहुत व्यापक है। यदि संदेश अनुप्रयोग व्यवसाय मॉडल का हिस्सा है, तो उसे आउटपुट देने के बारे में ध्यान नहीं रखना चाहिए। इसके बजाय, आप जिम्मेदारी को विभाजित कर सकते हैं और MessageDispatcher का उपयोग कर सकते हैं जो पाठ या HTML बैकएंड का उपयोग करके पारित संदेश भेजता है। मुझे आपका कोड नहीं पता, लेकिन मुझे इसे इस तरह अनुकरण करना चाहिए:

$m = new Message();
$m->type = 'text/html';
$m->from = 'John Doe <jdoe@yahoo.com>';
$m->to = 'Random Hacker <rh@gmail.com>';
$m->subject = 'Invitation email';
$m->importBody('invitation.html');

$d = new MessageDispatcher();
$d->dispatch($m);

इस तरह आप संदेश वर्ग में कुछ विशेषज्ञता जोड़ सकते हैं:

$htmlIM = new InvitationHTMLMessage(); // html type, subject and body configuration in constructor
$textIM = new InvitationTextMessage(); // text type, subject and body configuration in constructor

$d = new MessageDispatcher();
$d->dispatch($htmlIM);
$d->dispatch($textIM);

ध्यान दें कि MessageDispatcher एक निर्णय लेगा कि संदेश के रूप में HTML या सादे पाठ के रूप में भेजा जाना है या नहीं type

// in MessageDispatcher class
public function dispatch(Message $m) {
    if ($m->type == 'text/plain') {
        $this->sendAsText($m);
    } elseif ($m->type == 'text/html') {
        $this->sendAsHTML($m);
    } else {
        throw new Exception("MIME type {$m->type} not supported");
    }
}

इसे योग करने के लिए, जिम्मेदारी दो वर्गों के बीच विभाजित है। संदेश कॉन्फ़िगरेशन InvitationHTMLMessage / InvitationTextMessage वर्ग में किया जाता है, और एल्गोरिथ्म भेजने को डिस्पैचर में भेजा जाता है। इसे स्ट्रैटेजी पैटर्न कहा जाता है, आप यहां इस पर अधिक पढ़ सकते हैं ।


13
आश्चर्यजनक रूप से व्यापक जवाब, धन्यवाद! मैंने आज कुछ सीखा!
एलेक्स वीनस्टीन

26
... मुझे पता है कि यह थोड़ा पुराना है (मैं यह देखना चाह रहा था कि क्या PHP में MI था ... बस जिज्ञासा के लिए) मुझे नहीं लगता कि यह रणनीति पैटर्न का एक अच्छा उदाहरण है। रणनीति पैटर्न को डिज़ाइन किया गया है ताकि आप किसी भी समय एक नई "रणनीति" लागू कर सकें। आपके द्वारा प्रदान किए गए कार्यान्वयन में ऐसी क्षमता नहीं है। इसके बजाय, संदेश में "भेजें" फ़ंक्शन होना चाहिए जो MessageDispatcher-> डिस्पैच को बुलाता है (डिस्पैचर या तो एक परम या सदस्य संस्करण), और नई कक्षाएं HTMLDispatcher और TextDispatcher अपने संबंधित तरीकों से "प्रेषण" को लागू करेगा (यह अन्य डिस्पैचर करने की अनुमति देता है) अन्य कार्य)
टेरेंस होनल्स

12
दुर्भाग्य से PHP रणनीति पैटर्न को लागू करने के लिए महान नहीं है। ऐसी भाषाएँ जो समर्थन विधि को बेहतर तरीके से यहाँ लोड करने का काम करती हैं - कल्पना करें कि आपके पास एक ही नाम की दो विधियाँ हैं: प्रेषण (HTMLMessage $ m) और प्रेषण (TextMessage $) - अब दृढ़ता से टाइप की गई भाषा संकलक / दुभाषिया में स्वचालित रूप से सही "कार्यनीति" आधारित होगी। पैरामीटर का प्रकार। इसके अलावा, मुझे नहीं लगता कि नई रणनीति के कार्यान्वयन के लिए खुला होना रणनीति पैटर्न का सार है। यकीन है कि यह एक अच्छी बात है, लेकिन अक्सर एक आवश्यकता नहीं है।
मिशैल रुडनिक

2
मान लीजिए कि आपके पास एक वर्ग है Tracing(यह सिर्फ एक नमूना है) जहां आप एक फ़ाइल में डिबग जैसी सामान्य चीजें रखना चाहते हैं, महत्वपूर्ण समस्या के लिए एसएमएस भेजें और इसी तरह। आपके सभी वर्ग इस वर्ग के बच्चे हैं। अब मान लीजिए कि आप एक ऐसा वर्ग बनाना चाहते हैं जिसमें Exceptionउन कार्यों (= बच्चे Tracing) का होना चाहिए । इस वर्ग का एक बच्चा होना चाहिए Exception। आप एकाधिक उत्तराधिकार के बिना इस तरह के सामान को कैसे डिजाइन करते हैं ? हां, आपके पास हमेशा एक समाधान हो सकता है, लेकिन आप हमेशा हैकिंग के करीब पहुंचेंगे। और लंबे समय में हैकिंग = महंगा समाधान। कहानी का अंत।
ओलिवियर पोंस

1
ओलिवियर पोंस, मुझे नहीं लगता कि उपवर्ग ट्रेसिंग आपके उपयोग के मामले के लिए सही समाधान होगा। स्थैतिक विधियों डिबग, सेंडएमएस, आदि के साथ एक अमूर्त ट्रेसिंग क्लास के रूप में कुछ सरल है, जिसे बाद में ट्रेसिंग के साथ किसी भी अन्य वर्ग से बुलाया जा सकता है: SendSMS () आदि। आपकी अन्य कक्षाएं ट्रेसिंग के 'प्रकार' नहीं हैं, आदि। वे 'ट्रेसिंग' का उपयोग करते हैं। नोट: कुछ लोग स्थैतिक तरीकों पर एक सिंगलटन पसंद कर सकते हैं; मैं जहाँ संभव हो सिंगलनेट पर स्थिर विधियों का उपयोग करना पसंद करता हूँ।

15

हो सकता है कि आप एक 'है-ए' के ​​साथ एक 'है-ए' संबंध बदल सकते हैं? एक निमंत्रण में एक संदेश हो सकता है, लेकिन इसके लिए जरूरी नहीं है कि 'is-a' संदेश हो। एक निमंत्रण फ़र की पुष्टि की जा सकती है, जो संदेश मॉडल के साथ अच्छी तरह से नहीं जाता है।

'रचना बनाम वंशानुक्रम' की खोज करें यदि आपको इसके बारे में अधिक जानना है।


9

अगर मैं फिल को इस धागे में उद्धृत कर सकता हूं ...

जावा की तरह PHP, कई उत्तराधिकार का समर्थन नहीं करता है।

PHP 5.4 में आने वाले लक्षण होंगे जो इस समस्या का समाधान प्रदान करने का प्रयास करेंगे ।

इस बीच, आप अपनी कक्षा के डिजाइन पर फिर से विचार करने के लिए सर्वश्रेष्ठ होंगे। यदि आप अपनी कक्षाओं में विस्तारित एपीआई के बाद हैं तो आप कई इंटरफेस को लागू कर सकते हैं।

और क्रिस…।

PHP वास्तव में एकाधिक उत्तराधिकार का समर्थन नहीं करता है, लेकिन इसे लागू करने के कुछ (कुछ गड़बड़) तरीके हैं। कुछ उदाहरणों के लिए इस URL को देखें:

http://www.jasny.net/articles/how-i-php-multiple-inheritance/

सोचा कि वे दोनों उपयोगी लिंक थे। लक्षण या शायद कुछ मिश्रण की कोशिश करने के लिए इंतजार नहीं कर सकता ...


1
लक्षण जाने का रास्ता हैं
जोनाथन

6

सिम्फनी फ्रेमवर्क में इसके लिए एक मिक्सिन प्लगइन है , आप इसे जांचना चाह सकते हैं - यहां तक ​​कि सिर्फ विचारों के लिए, यदि इसका उपयोग नहीं करना है।

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


4

मैं इसे सुलझाने के तरीके के रूप में PHP 5.4 में लक्षण का उपयोग कर रहा हूं। http://php.net/manual/en/language.oop5.traits.php

यह फैली हुई क्लासिक विरासत के लिए अनुमति देता है, लेकिन यह भी सामान्य कार्यक्षमता और गुणों को एक 'विशेषता' में रखने की संभावना देता है। जैसा कि मैनुअल कहता है:

लक्षण PHP जैसे एकल विरासत भाषाओं में कोड पुन: उपयोग के लिए एक तंत्र है। एक विशेषता विभिन्न वर्ग पदानुक्रमों में रहने वाले कई स्वतंत्र वर्गों में स्वतंत्र रूप से तरीकों के सेट का पुन: उपयोग करने के लिए एक डेवलपर को सक्षम करके एकल वंशानुक्रम की कुछ सीमाओं को कम करने का इरादा है।



3

यह एक प्रश्न और एक समाधान दोनों है ...।

क्या जादुई _ कॉल के बारे में (),_get (), __set () विधियाँ? मैंने अभी तक इस समाधान का परीक्षण नहीं किया है लेकिन क्या होगा यदि आप एक मल्टीहेरिट वर्ग बनाते हैं। एक बाल वर्ग में एक संरक्षित चर में वंशानुक्रम वर्ग हो सकता है। मल्टी-इंटरफ़ेस क्लास में कंस्ट्रक्टर प्रत्येक वर्ग के उदाहरण बना सकता है जो विरासत में मिला है और उन्हें निजी संपत्ति से जोड़ते हैं, _ext कहते हैं। __Call () विधि कॉल करने के लिए सही विधि का पता लगाने के लिए _ext सरणी में प्रत्येक वर्ग पर method_exists () फ़ंक्शन का उपयोग कर सकती है। __get () और __set का उपयोग आंतरिक गुणों का पता लगाने के लिए किया जा सकता है, या यदि आपके संदर्भ के साथ एक विशेषज्ञ, तो आप बच्चे के वर्ग और विरासत में मिली कक्षाओं के गुणों को एक ही डेटा के संदर्भ में बना सकते हैं। आपकी ऑब्जेक्ट की कई विरासत उन वस्तुओं का उपयोग करके कोड के लिए पारदर्शी होगी। इसके अलावा, आंतरिक वस्तुएं विरासत में मिली वस्तुओं तक सीधे पहुंच सकती हैं, जब तक कि जरूरत है कि _ext सरणी वर्ग नाम से अनुक्रमित हो। मैंने इसे सुपर-क्लास बनाने की कल्पना की है और अभी तक इसे लागू नहीं किया है क्योंकि मुझे लगता है कि अगर यह काम करता है तो इससे कुछ अलग-अलग खराब प्रोग्रामिंग आदतों का विकास हो सकता है।


मुझे लगता है कि यह संभव है। यह कई वर्गों की कार्यक्षमता को संयोजित करेगा, लेकिन वास्तव में उन्हें (इन अर्थों में instanceof) विरासत में नहीं देगा
user102008

और यह निश्चित रूप से अतिदेय की अनुमति देने में विफल रहेगा जैसे ही आंतरिक वर्ग स्वयं को कॉल करता है :: <जो कुछ भी
फिल लेलो

1

मेरे पास कुछ प्रश्न हैं जो स्पष्ट करने के लिए कहें कि आप क्या कर रहे हैं:

1) क्या आपके संदेश की वस्तु में केवल एक संदेश है जैसे शरीर, प्राप्तकर्ता, शेड्यूल समय? 2) आप अपने निमंत्रण ऑब्जेक्ट के साथ क्या करने का इरादा रखते हैं? क्या इसे ईमेल मेसेजेज की तुलना में विशेष रूप से इलाज करने की आवश्यकता है? 3) यदि ऐसा है तो इसके बारे में क्या खास है? ४) यदि ऐसा है, तो निमंत्रण के लिए संदेश प्रकारों को अलग-अलग संभालने की आवश्यकता क्यों है? 5) यदि आप स्वागत संदेश या ओके संदेश भेजना चाहते हैं तो क्या होगा? क्या वे नई वस्तुएं भी हैं?

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

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


0

जावा जैसी ही समस्या। उस समस्या को हल करने के लिए अमूर्त कार्यों के साथ इंटरफेस का उपयोग करने का प्रयास करें


0

PHP सपोर्ट इंटरफेस बनाती है। आपके उपयोग के मामलों के आधार पर यह एक अच्छा दांव हो सकता है।


5
इंटरफेस ठोस कार्य कार्यान्वयन के लिए अनुमति नहीं देते हैं, इसलिए वे यहां सहायक नहीं हैं।
एलेक्स वेनस्टेन

1
इंटरफेसेस कक्षाओं के विपरीत मल्टीपल इनहेरिटेंस का समर्थन करते हैं।
क्रेग लुईस

-1

संदेश वर्ग के ठीक नीचे एक निमंत्रण वर्ग कैसे होता है?

इसलिए पदानुक्रम चला जाता है:

संदेश
--- निमंत्रण
------ TextMessage
------ EmailMessage

और निमंत्रण वर्ग में, कार्यक्षमता जोड़ें जो InvitationTextMessage और InvitationEmailMessage में थी।

मुझे पता है कि निमंत्रण वास्तव में संदेश का एक प्रकार नहीं है, यह संदेश की अधिक कार्यक्षमता है। तो मुझे यकीन नहीं है कि यह अच्छा ओओ डिजाइन है या नहीं।

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