2012-06-30 7 views
8

मैं एक मॉड्यूल (फ्रेमवर्क विशिष्ट) लिखना चाहता हूं, जो फेसबुक PHP-sdk (https://github.com/facebook/php-sdk/) को लपेट और विस्तारित करेगा। मेरी समस्या यह है कि - अच्छी तरह से कक्षाओं को व्यवस्थित करने के लिए कैसे।बहु स्तरीय विरासत प्रतिस्थापन

तो विस्तार में हो रही - फेसबुक पीएचपी-sdk दो वर्गों के होते हैं:

  • BaseFacebook - फैली BaseFacebook, और लागू करता है माता पिता सार दृढ़ता से संबंधित तरीकों - सार वर्ग सब सामान SDK के साथ
  • फेसबुक करता है डिफ़ॉल्ट सत्र उपयोग के साथ

अब मैं जोड़ने के लिए कुछ कार्यक्षमता है:

  • फेसबुक वर्ग प्रतिस्थापन, ढांचा सत्र वर्ग के साथ एकीकृत
  • आशुलिपि तरीकों, कि रन API कॉल, मैं ज्यादातर का उपयोग करें (BaseFacebook के माध्यम से :: एपीआई()),
  • प्राधिकरण के तरीकों, तो मैं यह फिर से लिखने की जरूरत नहीं है तर्क हर बार,
  • विन्यास, फ्रेमवर्क वर्गों से चूसा, पारित कर दिया के रूप में पैरामीटर
  • कैशिंग, ढांचा कैश मॉड्यूल के साथ एकीकृत

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

शायद यहां कुछ प्रकार का पैटर्न सही होगा? आप इन वर्गों और उनकी निर्भरताओं को कैसे व्यवस्थित करेंगे?

संपादित 04.07.2012

कोड के टुकड़े, विषय से संबंधित:

इस तरह फेसबुक पीएचपी-sdk के आधार वर्ग है:

abstract class BaseFacebook { 

    // ... some methods 

    public function api(/* polymorphic */) 
    { 
     // ... method, that makes api calls 
    } 

    public function getUser() 
    { 
     // ... tries to get user id from session 
    } 

    // ... other methods 

    abstract protected function setPersistentData($key, $value); 

    abstract protected function getPersistentData($key, $default = false); 

    // ... few more abstract methods 

} 

Normaly फेसबुक वर्ग फैली यह, और उन सार तरीकों का पालन करता है। मैं अपने substitude से बदल दिया - Facebook_Session वर्ग:

class Facebook_Session extends BaseFacebook { 

    protected function setPersistentData($key, $value) 
    { 
     // ... method body 
    } 

    protected function getPersistentData($key, $default = false) 
    { 
     // ... method body 
    } 

    // ... implementation of other abstract functions from BaseFacebook 
} 

ठीक है, तो मैं इस अधिक आशुलिपि तरीकों और विन्यास चर के साथ विस्तार:

class Facebook_Custom extends Facebook_Session { 

    public function __construct() 
    { 
     // ... call parent's constructor with parameters from framework config 
    } 

    public function api_batch() 
    { 
     // ... a wrapper for parent's api() method 
     return $this->api('/?batch=' . json_encode($calls), 'POST'); 
    } 

    public function redirect_to_auth_dialog() 
    { 
     // method body 
    } 

    // ... more methods like this, for common queries/authorization 

} 

मुझे यकीन नहीं कर रहा हूँ अगर यह भी नहीं है एक वर्ग के लिए बहुत कुछ (प्राधिकरण/लघुरूप विधियों/विन्यास)। फिर एक और विस्तार परत - कैश:

class Facebook_Cache extends Facebook_Custom { 

    public function api() 
    { 
     $cache_file_identifier = $this->getUser(); 

     if(/* cache_file_identifier is not null 
       and found a valid file with cached query result */) 
     { 
      // return the result 
     } 
     else 
     { 
      try { 
       // call Facebook_Custom::api, cache and return the result 
      } catch(FacebookApiException $e) { 
       // if Access Token is expired force refreshing it 
       parent::redirect_to_auth_dialog(); 
      } 
     } 

    } 

    // .. some other stuff related to caching 

} 

अब यह बहुत अधिक काम करता है। Facebook_Cache का नया उदाहरण मुझे सभी कार्यक्षमता देता है। फेसबुक_Custom से शॉर्टंड विधियों का उपयोग कैशिंग, क्योंकि फेसबुक_Cache ने एपीआई() विधि को ओवरराइट किया है।लेकिन यहां मुझे परेशान कर रहा है:

  • मुझे लगता है कि यह बहुत अधिक विरासत है।
  • यह सब बहुत तंग युग्मित है - जैसा दिखता है कि मुझे फेसबुक पैरेंट पर एपीआई() विधि लूप से बचने के लिए 'parent: api' के बजाय 'फेसबुक_Custom :: api' निर्दिष्ट करना था।
  • कुल मिलाकर गड़बड़ और कुरूपता।

तो फिर, यह काम करता है लेकिन मैं सिर्फ क्लीनर और स्मार्ट तरीके से ऐसा करने के पैटर्न/तरीकों के बारे में पूछ रहा हूं।

+0

कृपया प्रदान करते हैं कुछ और जानकारी समाधान के लिए पास अधिक प्राप्त करने के लिए .. –

+0

मैं कोड बिट्स को शामिल किया है, sory कि यह इतना समय लगा। – Luigi

+3

वैसे; एकाधिक विरासत एक वर्ग से अधिक एक वर्ग का विस्तार कर रही है। यह कुछ अलग है। – Sherlock

उत्तर

2

कैशिंग जैसे सहायक सुविधाएं आमतौर पर एक सजावटी के रूप में लागू की जाती हैं (जो मुझे लगता है कि आपने पहले ही किसी अन्य टिप्पणी में उल्लेख किया है)। सज्जाकार इंटरफेस के साथ सबसे अच्छा काम करते हैं, तो मैं एक बनाने से शुरू होगा:

interface FacebookService { 
    public function api(); 
    public function getUser(); 
} 

रख सरल, कुछ भी आप (जैसे setPersistentData के रूप में) बाहर से की जरूरत नहीं है न जोड़ें।फिर अपने नए इंटरफ़ेस मौजूदा BaseFacebook वर्ग लपेट:

class CachingFacebookService implements FacebookService { 
    private $fb; 

    function __construct(FacebookService $fb) { 
    $this->fb = $fb; 
    } 

    public function api() { 
    // put caching logic here and maybe call $fb->api 
    } 

    public function getUser() { 
    return $fb->getUser(); 
    } 
} 

और फिर:

class FacebookAdapter implements FacebookService { 
    private $fb; 

    function __construct(BaseFacebook $fb) { 
    $this->fb = $fb; 
    } 

    public function api() { 
    // retain variable arguments 
    return call_user_func_array(array($fb, 'api'), func_get_args()); 
    } 

    public function getUser() { 
    return $fb->getUser(); 
    } 
} 

अब यह एक कैशिंग डेकोरेटर लिखने के लिए आसान है

$baseFb = new Facebook_Session(); 
$fb = new FacebookAdapter($baseFb); 
$cachingFb = new CachingFacebookService($fb); 

दोनों $fb और $cachingFb का पर्दाफाश वही FacebookService इंटरफ़ेस - ताकि आप यह चुन सकें कि आप कैशिंग चाहते हैं या नहीं, और शेष कोड बिल्कुल नहीं बदलेगा।

आपके Facebook_Custom कक्षा के लिए, यह अभी केवल सहायक तरीकों का एक गुच्छा है; आपको इसे एक या अधिक स्वतंत्र वर्गों में कारक बनाना चाहिए जो FacebookService को लपेटें और विशिष्ट कार्यक्षमता प्रदान करें। कुछ उदाहरण उपयोग के मामलों:

$x = new FacebookAuthWrapper($fb); 
$x->redirect_to_auth_dialog(); 

$x = new FacebookBatchWrapper($fb); 
$x->api_batch(...); 
+0

अधिक व्यापक और अच्छी तरह से प्रबंधित, पोस्ट के लिए धन्यवाद। –

+0

क्या होगा यदि कुछ सेवाओं को बेसफ़ेसबुक से एपीआई() और getUser() से अधिक फ़ंक्शंस की आवश्यकता है? इंटरफेस में और अधिक कार्य होना चाहिए? शायद _call का उपयोग करें? लेकिन फिर इंटरफ़ेस की वास्तव में कोई आवश्यकता नहीं है, और एक सेवा बेसफ़ेसबुक वंश या अन्य सेवा दोनों प्राप्त कर सकती है ... – Luigi

+0

@ लुइगी: यदि आपको आवश्यकता हो तो आप उन्हें इंटरफ़ेस में जोड़ सकते हैं। मैं '__call' जैसे जादू विधियों से दूर रहूंगा क्योंकि वे ओओ डिज़ाइन को तोड़ना आसान बनाते हैं। – casablanca

0

मुझे लगता है कि इस स्थिति में भंडार डिजाइन पैटर्न बेहतर होगा। हालांकि मैं php से नहीं हूं लेकिन ओप्स के अनुसार इसे आपके मुद्दे को हल करना चाहिए ..

2

यह वास्तव में बहुत अधिक विरासत है। Facade डिजाइन पैटर्न के लिए एक नौकरी की तरह लग रहा है। अधिक लचीलापन रखने के लिए विरासत की बजाय संरचना का प्रयोग करें। उचित वस्तुओं के लिए उपयोग की जाने वाली किसी भी विधि को प्रतिनिधि दें।

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

आम तौर पर हाँ, एक वर्ग में कई जिम्मेदारियों को असाइन करना एक अच्छा विचार नहीं है। यहां, कक्षा की ज़िम्मेदारी बाहरी एपीआई का प्रतिनिधित्व करना होगा।

2

मुझे लगता है कि जैसे कुछ बात किया है याहू SDK के लिए मुझे डाल दिया है, यह एक कोशिश :)

चलें मान फेसबुक एसडीके में वर्ग आप सभी अंत विधि कॉल के लिए उपयोग कर रहे हैं दे। आप एक नई कक्षा बना सकते हैं (जैसा कि आपका फ्रेम काम करता है) और कक्षा के एक चर को फेसबुक क्लास के उदाहरण के लिए असाइन करें।

फेसबुक के सभी तरीकों के लिए __call() का उपयोग करें और अपने custome लोगों को रैपर वर्ग में रखें। सभी अपरिभाषित तरीकों के लिए यह रैपर है, यह फेसबुक क्लास पर जाएगा और इसमें कोई विरासत शामिल नहीं है। यह मेरे लिए काम किया। आशा है कि यह मदद करता है :)

Class MyWrapper 
    { 
     protected $facebook; 
     public function __construct() 
     { 
      $this->facebook = new FaceBook(); 
     } 

     public function __call($method,$args) 
     { 
      return $this->facebook->$method($args); 
     } 

     ///define Your methods ////////// 

     /////////////////////////////////// 
    } 

    $t = new MyWrap; 
    $t->api(); // Whatever !!!! 

संपादित:

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

Class MyWrapper 
    { 
     protected $facebook; 
     protected $facebookCache; 
     public function __construct() 
     { 
      $this->facebook = new FaceBook(); 
      $this->facebookCache = new FacebookCache(); 
     } 

     public function __call($method,$args) 
     { 
      $method = explode('_',$method); 
      $instance_name = $method[0]; 
      $method_name = $method[1]; 
      return $this->$instance_name->$method_name($args); 
     } 

     ///define Your methods ////////// 

     /////////////////////////////////// 
    } 

    $t = new MyWrap; 
    $t->facebook_api(); // Whatever !!!! 
    $t->facebookCache_cache(); 
+1

मैंने इस आखिरी शाम के बारे में सोचा है। मुझे लगता है कि इसे 'सजावट पैटर्न' कहा जाता है। यह अच्छा है, हालांकि मुझे अभी भी एक चीज़ के बारे में संदेह है। मुझे इस तरह के कुछ रैपर होने की जरूरत है। कैशिंग के लिए एक की तरह, एक शोरहैंड विधियों के लिए, एक प्राधिकरण के लिए। अब मैं एक सौम्य तरीके से कई सजावट का उपयोग कैसे कर सकता हूं? उनमें से एक संयोजन लोड करने के लिए एक अलग वर्ग (रणनीति पैटर्न/fascade)? शायद आपके पास कोई विचार है? – Luigi

+0

मैंने अपना जवाब संपादित कर लिया है, उम्मीद है कि यह मदद करेगा :) –

+0

MyWrapper क्लास के एपीआई को संपादित करने के बाद व्यापक है, लेकिन अब फेसबुक कैश दोनों सीधे फेसबुक क्लास का उपयोग नहीं कर सकते हैं और माइक्रैपर विधियों के साथ सहयोग के लिए additnioal शर्तों/हार्डकोडिंग की आवश्यकता होगी। मैं आपका पहला उदाहरण बेहतर पसंद करता हूं। मैं एक कन्स्ट्रक्टर पैराम जोड़ सकता हूं और इसका उपयोग कर सकता हूं: '$ fb = new Facebook(); $ fbCache = नया फेसबुक कैश ($ एफबी); $ shorthand = नया फेसबुकशर्थेंड ($ एफबीसीएसी); $ shorthandNoCache फेसबुकशर्थैंड ($ एफबी); 'आदि। तो - ढीला युग्मन। शोरहैंड कक्षा इसे जानने के बिना कैशिंग का उपयोग कर सकती है। यदि बक्षीस समय समाप्त होने से पहले कुछ भी बेहतर नहीं होता है तो मैं आपका जवाब स्वीकार करूंगा :)। धन्यवाद। – Luigi

संबंधित मुद्दे