2012-06-09 20 views
12

मैं जोशुआ ब्लोच द्वारा प्रभावी जावा के माध्यम से पढ़ रहा हूं। मैं PHP में भी विकसित हूं और मैं builder pattern outlined in item 2 को कार्यान्वित करना चाहता था, लेकिन PHP में आंतरिक कक्षाएं नहीं हैं। क्या पीएचपी में इस पैटर्न को हासिल करने का कोई तरीका है, उत्पाद के लिए निर्माता को निजी रखना?आंतरिक कक्षाओं के बिना PHP बिल्डर पैटर्न

+0

जबकि प्रश्न का समाधान है, ऐसे कार्यान्वयन का मूल्य बहुत कम हो गया है। PHP अपरिवर्तनीयता के आसपास नहीं बना है, इसलिए एकमात्र लाभ जंजीर तरीकों से होगा। JavaBeans पैटर्न का उपयोग PHP में स्वीकार्य समाधान है। – danidacar

उत्तर

27

PHP does not support inner classes के बाद से, उत्पाद वर्ग पर एक सार्वजनिक विधि होनी चाहिए जो इसका एक उदाहरण बनाता है। निम्नलिखित पीएचपी वर्गों पर विचार करें:

<?php 
class NutritionalFactsBuilder { 
    private $sodium; 
    private $fat; 
    private $carbo; 

    /** 
    * It is preferred to call NutritionalFacts::createBuilder 
    * to calling this constructor directly. 
    */ 
    function __construct($s) { 
     $this->sodium = $s; 
    } 

    function fat($f) { 
     $this->fat = $f; 
     return $this; 
    } 

    function carbo($c) { 
     $this->carbo = $c; 
     return $this; 
    } 

    function getSodium() { 
     return $this->sodium; 
    } 

    function getFat() { 
     return $this->fat; 
    } 

    function getCarbo() { 
     return $this->carbo; 
    } 

    function build() { 
     return new NutritionalFacts($this); 
    } 
} 

class NutritionalFacts { 
    private $sodium; 
    private $fat; 
    private $carbo; 

    static function createBuilder($s) { 
     return new NutritionalFactsBuilder($s); 
    } 

    /** 
    * It is preferred to call NutritionalFacts::createBuilder 
    * to calling this constructor directly. 
    */ 
    function __construct(NutritionalFactsBuilder $b) { 
     $this->sodium = $b->getSodium(); 
     $this->fat = $b->getFat(); 
     $this->carbo = $b->getCarbo(); 
    } 
} 

echo '<pre>'; 
var_dump(NutritionalFacts::createBuilder(10)->fat(23)->carbo(1)->build()); 
echo '</pre>'; 
?> 

ध्यान दें कि ऊपर के उदाहरण में NutritionalFacts के निर्माता सार्वजनिक है। भाषा की बाधाओं के कारण, हालांकि, एक सार्वजनिक कन्स्ट्रक्टर होने पर बुरा नहीं है। चूंकि किसी को NutritionalFactsBuilder के साथ कन्स्ट्रक्टर को कॉल करना होगा, इसलिए NutritionalFacts को तुरंत चालू करने के लिए सीमित संख्या में तरीके हैं। के उनकी तुलना करते हैं:

// NutritionalFacts Instantiation #0 
$nfb = new NutritionalFactsBuilder(10); 
$nfb = $nfb->fat(23)->carbo(1); 
$nf0 = new NutritionalFacts($nfb); 

// NutritionalFacts Instantiation #1 
$nfb = new NutritionalFactsBuilder(10); 
$nf1 = $nfb->fat(23)->carbo(1)->build(); 

// NutritionalFacts Instantiation #2 
$nf2 = NutritionalFacts::createBuilder(10)->fat(23)->carbo(1)->build(); 

// NutritionalFacts Instantiation #3 
// $nf3 = (new NutritionalFactsBuilder(10))->fat(23)->carbo(1)->build(); 

समारोह का लाभ उठाने के लिए अपने पूर्ण सीमा तक चेनिंग, "NutritionalFacts प्रारंभ # 2" पसंदीदा उपयोग है।

" NutritionalFacts प्रारंभ # 3" पीएचपी वाक्य रचना का एक और अति सूक्ष्म अंतर पता चलता है; one cannot chain a method on a newly instantiated object. अपडेट: PHP 5.4.0 में, अब support for the syntax "NutritionalFacts इंस्टेंटेशन # 3" में है। मैंने अभी तक इसका परीक्षण नहीं किया है।


निर्माता निजी

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

class NutritionalFacts { 
    private $sodium; 
    private $fat; 
    private $carbo; 

    static function createBuilder($s) { 
     return new NutritionalFactsBuilder($s); 
    } 

    static function createNutritionalFacts($builder) { 
     return new NutritionalFacts($builder); 
    } 

    private function __construct($b) { 
     $this->sodium = $b->getSodium(); 
     $this->fat = $b->getFat(); 
     $this->carbo = $b->getCarbo(); 
    } 
} 
+0

यह सही है। धन्यवाद, आपने पूरी तरह से मेरे प्रश्न का उत्तर दिया। – Jackson

+0

इसके अलावा, आपने देखा है कि आप PHP 5.4 में एक नई तत्काल वस्तु पर एक विधि को श्रृंखलाबद्ध कर सकते हैं: http://docs.php.net/manual/en/migration54.new-features.php – Jackson

+0

@ जैक्सन ओवेन्स यह शानदार है। Http://stackoverflow.com/questions/2188629 के उत्तर के रूप में आपने अभी जो कहा है उसे जोड़ें। मुझे लगता है कि यह दूसरों के लिए उपयोगी होगा। – creemama

1

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

आप पीएचपी बिल्डर पैटर्न के उदाहरण के बहुत सारे पा सकते हैं:

http://www.php5dp.com/category/design-patterns/builder/

चीयर्स, विधेयक

1

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

कहा जा रहा है कि आंतरिक कक्षाओं के बिना भी अपरिवर्तनीय वस्तुओं को बनाने के लिए बिल्डर पैटर्न को कार्यान्वित करने का एक आसान तरीका है (हालांकि अब PHP 7 के साथ उपलब्ध है)।

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

abstract class NutritionalFactData { 

    protected $sodium = 0; 
    protected $fat = 0; 
    protected $carbo = 0; 

    protected function __clone() {} 

} 

अपरिवर्तनीय वर्ग बेवकूफ उदाहरण गेटर्स और एक निजी निर्माता के साथ सीधे आगे है। कक्षा के लिए final संशोधक पर ध्यान दें और यह कि बिल्डर वर्ग के बारे में पता नहीं है।

final class NutritionalFacts extends NutritionalFactData { 

    public function getSodium() { 
     return $this->sodium; 
    } 

    public function getFat() { 
     return $this->fat; 
    } 

    public function getCarbo() { 
     return $this->carbo; 
    } 

    private function __construct() {} 

} 

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

final class NutritionalFactBuilder extends NutritionalFactData { 

    private $nutritional_facts; 

    public function __construct() { 
     $this->nutritional_facts = new NutritionalFacts; 
    } 

    public function build() { 
     return clone $this->nutritional_facts; 
    } 

    public function setSodium($sodium) { 
     $this->nutritional_facts->sodium = $sodium; 
     return $this; 
    } 

    public function setFat($fat) { 
     $this->nutritional_facts->fat = $fat; 
     return $this; 
    } 

    public function setCarbo($carbo) { 
     $this->nutritional_facts->carbo = $carbo; 
     return $this; 
    } 

} 
पूर्णता के लिए

एक के उपयोग का उदाहरण:

var_dump(
    (new NutritionalFactBuilder) 
     ->setSodium(21) 
     ->setFat(42) 
     ->build() 
); 

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

abstract class CarParts {} 

final class Car extends CarParts {} 

abstract class CarBuilder extends CarParts { 
    abstract public function build(): Car; 
} 

final class CompactCarBuilder extends CarBuilder {} 

final class SportsCarBuilder extends CarBuilder {} 

final class RaceCarBuilder extends CarBuilder {} 
संबंधित मुद्दे