java - आप बिल्डर पैटर्न का उपयोग कब करेंगे?




design-patterns builder (10)

बिल्डर पैटर्न का उपयोग करने के कुछ सामान्य , असली दुनिया के उदाहरण क्या हैं? यह आपको क्या खरीदता है? फैक्टरी पैटर्न का उपयोग क्यों न करें?


.NET स्ट्रिंगबिल्डर वर्ग बिल्डर पैटर्न का एक बड़ा उदाहरण है। इसका उपयोग ज्यादातर चरणों की श्रृंखला में एक स्ट्रिंग बनाने के लिए किया जाता है। ToString () करने पर आपको जो अंतिम परिणाम मिलता है वह हमेशा एक स्ट्रिंग होता है लेकिन उस स्ट्रिंग का निर्माण स्ट्रिंगबिल्डर वर्ग में किए गए कार्यों के अनुसार भिन्न होता है। संक्षेप में, बुनियादी विचार जटिल वस्तुओं का निर्माण करना और कार्यान्वयन के विवरण को छिपाना है कि यह कैसे बनाया जा रहा है।


इंटेलबिल्डर, एक इंटेलिजे आईडीईए प्लगइन देखें जो जेनरेट मेनू (Alt + Insert) में 'बिल्डर' एक्शन जोड़ता है जो प्रभावी जावा में वर्णित एक आंतरिक बिल्डर क्लास उत्पन्न करता है

https://github.com/analytically/innerbuilder


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

क्या हम इसके बजाय कारखाने का उपयोग कर सकते हैं? हाँ

हम क्यों नहीं थे मुझे लगता है कि बिल्डर अधिक समझ में आता है।

कारखानों का उपयोग विभिन्न प्रकार की वस्तुओं को बनाने के लिए किया जाता है जो समान मूल प्रकार (समान इंटरफेस या बेस क्लास को लागू करते हैं)।

बिल्डर्स एक ही प्रकार की वस्तु का निर्माण करते हैं, लेकिन निर्माण गतिशील है इसलिए इसे रनटाइम पर बदला जा सकता है।


एक रेस्तरां पर विचार करें। "आज का भोजन" का निर्माण एक कारखाना पैटर्न है, क्योंकि आप रसोईघर को "मुझे आज का भोजन प्राप्त करें" बताते हैं और रसोई (कारखाना) छुपा मानदंडों के आधार पर उत्पन्न होने वाली वस्तु का निर्णय लेता है।

यदि आप कस्टम पिज्जा ऑर्डर करते हैं तो बिल्डर दिखाई देता है। इस मामले में, वेटर शेफ (निर्माता) को बताता है "मुझे एक पिज्जा चाहिए; इसमें पनीर, प्याज और बेकन जोड़ें!" इस प्रकार, निर्माता उत्पन्न वस्तु के गुणों को उजागर करता है, लेकिन उन्हें सेट करने के तरीके को छुपाता है।


जब मैं जावा में डेटटाइम के मार्शलिंग को ऑब्जेक्ट करने के लिए अपने एक्सएमएल के लिए मानक एक्सएमएल ग्रेगोरियन कैलेंडर का उपयोग करना चाहता था, तो मैंने बहुत सारी टिप्पणियां सुनीं कि इसका वजन कितना भारी और बोझिल था। मैं xs में XML फ़ील्ड को कम करने की कोशिश कर रहा था: टाइमज़ोन, मिलीसेकंड आदि का प्रबंधन करने के लिए डेटाटाइम structs।

इसलिए मैंने एक ग्रेगोरियन कैलेंडर या java.util.Date से XMLGregorian कैलेंडर बनाने के लिए उपयोगिता तैयार की है।

जहां मैं काम करता हूं, मुझे कानूनी रूप से इसे ऑनलाइन साझा करने की अनुमति नहीं है, लेकिन यहां एक उदाहरण है कि क्लाइंट इसका उपयोग कैसे करता है। यह विवरणों को सारणीबद्ध करता है और XMLGregorianCalendar के कुछ कार्यान्वयन को फ़िल्टर करता है जो xs: डेटाटाइम के लिए कम उपयोग किए जाते हैं।

XMLGregorianCalendarBuilder builder = XMLGregorianCalendarBuilder.newInstance(jdkDate);
XMLGregorianCalendar xmlCalendar = builder.excludeMillis().excludeOffset().build();

यह पैटर्न एक फ़िल्टर से अधिक है क्योंकि यह xmlCalendar में फ़ील्ड को अपरिभाषित के रूप में सेट करता है, इसलिए उन्हें बाहर रखा गया है, यह अभी भी "इसे बनाता है"। मैंने xs: date, और xs: टाइम स्ट्रक्चर बनाने के लिए बिल्डर को अन्य विकल्प आसानी से जोड़े हैं और आवश्यकता होने पर टाइमज़ोन ऑफसेट्स को हेरफेर करने के लिए भी।

यदि आपने कभी ऐसा कोड देखा है जो XMLGregorianCalendar बनाता है और उसका उपयोग करता है, तो आप देखेंगे कि इससे कैसे छेड़छाड़ करना आसान हो गया है।


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

जैसा कि यहोशू ब्लोच प्रभावी जावा में बताता है , दूसरा संस्करण :

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

हम सभी ने कुछ बिंदुओं पर रचनाकारों की एक सूची के साथ एक वर्ग का सामना किया है जहां प्रत्येक अतिरिक्त एक नया विकल्प पैरामीटर जोड़ता है:

Pizza(int size) { ... }        
Pizza(int size, boolean cheese) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni) { ... }    
Pizza(int size, boolean cheese, boolean pepperoni, boolean bacon) { ... }

इसे टेलीस्कोपिंग कन्स्ट्रक्टर पैटर्न कहा जाता है। इस पैटर्न के साथ समस्या यह है कि एक बार कन्स्ट्रक्टर 4 या 5 पैरामीटर लंबे समय तक पैरामीटर के आवश्यक क्रम को याद रखना मुश्किल हो जाता है और साथ ही किसी विशेष परिस्थिति में आप जो विशेष कन्स्ट्रक्टर चाहें उसे याद रखना मुश्किल हो जाता है।

टेलीस्कोपिंग कन्स्ट्रक्टर पैटर्न के लिए आपके पास एक विकल्प जावाबीन पैटर्न है जहां आप अनिवार्य पैरामीटर के साथ एक कन्स्ट्रक्टर को कॉल करते हैं और उसके बाद किसी भी वैकल्पिक सेटर्स को कॉल करते हैं:

Pizza pizza = new Pizza(12);
pizza.setCheese(true);
pizza.setPepperoni(true);
pizza.setBacon(true);

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

बिल्डर पैटर्न का उपयोग करना बेहतर विकल्प है।

public class Pizza {
  private int size;
  private boolean cheese;
  private boolean pepperoni;
  private boolean bacon;

  public static class Builder {
    //required
    private final int size;

    //optional
    private boolean cheese = false;
    private boolean pepperoni = false;
    private boolean bacon = false;

    public Builder(int size) {
      this.size = size;
    }

    public Builder cheese(boolean value) {
      cheese = value;
      return this;
    }

    public Builder pepperoni(boolean value) {
      pepperoni = value;
      return this;
    }

    public Builder bacon(boolean value) {
      bacon = value;
      return this;
    }

    public Pizza build() {
      return new Pizza(this);
    }
  }

  private Pizza(Builder builder) {
    size = builder.size;
    cheese = builder.cheese;
    pepperoni = builder.pepperoni;
    bacon = builder.bacon;
  }
}

ध्यान दें कि पिज्जा अपरिवर्तनीय है और पैरामीटर मान सभी एक ही स्थान पर हैं । चूंकि बिल्डर के सेटर विधियों ने बिल्डर ऑब्जेक्ट को वापस कर दिया है, इसलिए वे जंजीर हो सकते हैं

Pizza pizza = new Pizza.Builder(12)
                       .cheese(true)
                       .pepperoni(true)
                       .bacon(true)
                       .build();

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

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


पिछले उत्तरों (पन इरादा) पर निर्माण, एक उत्कृष्ट असली दुनिया का उदाहरण है Groovy Builders लिए समर्थन में बनाया गया है।

ग्रोवी दस्तावेज़ीकरण में Builders देखें


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

मैं बिल्डर पैटर्न का उपयोग करने में जो लाभ देखता हूं वह यह है कि, आप अपना खुद का कारखाना बना सकते हैं और इसे ढांचे में प्लग कर सकते हैं।

@ टीथा, इतालवी रेस्तरां द्वारा संचालित एक रेस्तरां (फ्रेमवर्क) हो सकता है, जो पिज्जा परोसता है। पिज्जा इतालवी लड़का तैयार करने के लिए (ऑब्जेक्ट बिल्डर) पिज्जा बेस (बेस क्लास) के साथ ओवेन (फैक्ट्री) का उपयोग करता है।

अब भारतीय लड़का इतालवी लड़के से रेस्तरां लेता है। पिज्जा के बजाय भारतीय रेस्तरां (फ्रेमवर्क) सर्वर डोसा। डोसा भारतीय आदमी (ऑब्जेक्ट बिल्डर) तैयार करने के लिए एक मैडा (बेस क्लास) के साथ फ्राइंग पैन (फैक्ट्री) का उपयोग करता है

यदि आप परिदृश्य को देखते हैं, तो भोजन अलग होता है, जिस तरह से खाना तैयार किया जाता है, वह अलग होता है, लेकिन उसी रेस्तरां में (उसी ढांचे के नीचे)। रेस्तरां को इस तरह से बनाया जाना चाहिए कि यह चीनी, मैक्सिकन या किसी भी व्यंजन का समर्थन कर सके। ढांचे के अंदर ऑब्जेक्ट बिल्डर आपके इच्छित प्रकार के व्यंजनों को प्लगइन करने में सुविधा प्रदान करता है। उदाहरण के लिए

class RestaurantObjectBuilder
{
   IFactory _factory = new DefaultFoodFactory();

   //This can be used when you want to plugin the 
   public void SetFoodFactory(IFactory customFactory)
   {
        _factory = customFactory;
   }

   public IFactory GetFoodFactory()
   {
      return _factory;
   }
}

मैंने घर से उगाई गई मैसेजिंग लाइब्रेरी में बिल्डर का इस्तेमाल किया। लाइब्रेरी कोर तार से डेटा प्राप्त कर रहा था, इसे बिल्डर इंस्टेंस के साथ इकट्ठा कर रहा था, फिर, एक बार बिल्डर ने फैसला किया कि उसे संदेश उदाहरण बनाने के लिए आवश्यक सब कुछ मिल गया है, Builder.GetMessage () से एकत्र किए गए डेटा का उपयोग करके एक संदेश उदाहरण बना रहा था तार।


यूनिट का परीक्षण करने के लिए यूनिट का उपयोग करना एक महान वास्तविक दुनिया का उदाहरण है। आप सूट (सिस्टम अंडर टेस्ट) बिल्डर्स का उपयोग करते हैं।

उदाहरण:

वर्ग:

public class CustomAuthenticationService
{
    private ICloudService _cloudService;
    private IDatabaseService _databaseService;

    public CustomAuthenticationService(ICloudService cloudService, IDatabaseService databaseService)
    {
        _cloudService = cloudService;
        _databaseService = databaseService;
    }

    public bool IsAuthorized(User user)
    {            
        //Implementation Details
        return true;

}

परीक्षा:

    [Test]
    public void Given_a_User_With_Permission_When_Verifying_If_Authorized_Then_Authorize_It_Returning_True()
    {
        CustomAuthenticationService sut = new CustomAuthenticationServiceBuilder();
        User userWithAuthorization = null;

        var result = sut.IsAuthorized(userWithAuthorization);

        Assert.That(result, Is.True);
    }

sut बिल्डर:

public class CustomAuthenticationServiceBuilder
{
    private ICloudService _cloudService;
    private IDatabaseService _databaseService;

    public CustomAuthenticationServiceBuilder()
    {
        _cloudService = new AwsService();
        _databaseService = new SqlServerService();
    }

    public CustomAuthenticationServiceBuilder WithAzureService(AzureService azureService)
    {
        _cloudService = azureService;

        return this;
    }

    public CustomAuthenticationServiceBuilder WithOracleService(OracleService oracleService)
    {
        _databaseService = oracleService;

        return this;
    }

    public CustomAuthenticationService Build()
    {
        return new CustomAuthenticationService(_cloudService, _databaseService);
    }

    public static implicit operator CustomAuthenticationService (CustomAuthenticationServiceBuilder builder)
    {
        return builder.Build();
    }
}





builder