CodeGym /Java Blog /अनियमित /विरोधी पैटर्न क्या हैं? आइए कुछ उदाहरण देखें (भाग 1)
John Squirrels
स्तर 41
San Francisco

विरोधी पैटर्न क्या हैं? आइए कुछ उदाहरण देखें (भाग 1)

अनियमित ग्रुप में प्रकाशित
सबके लिए दिन अच्छा हो! दूसरे दिन मेरा जॉब इंटरव्यू था, और मुझसे एंटी-पैटर्न के बारे में कुछ सवाल पूछे गए: वे क्या हैं, किस प्रकार के हैं, और कौन से व्यावहारिक उदाहरण हैं। बेशक, मैंने सवाल का जवाब दिया, लेकिन बहुत ही सतही तौर पर, क्योंकि मैंने पहले इस विषय में गहराई से नहीं डाला था। साक्षात्कार के बाद, मैंने इंटरनेट खंगालना शुरू किया और विषय में खुद को अधिक से अधिक डुबो दिया। विरोधी पैटर्न क्या हैं?  आइए कुछ उदाहरण देखें (भाग 1) - 1 आज मैं सबसे लोकप्रिय एंटी-पैटर्न का संक्षिप्त विवरण देना चाहता हूं और कुछ उदाहरणों की समीक्षा करना चाहता हूं। मुझे उम्मीद है कि इसे पढ़ने से आपको इस क्षेत्र में आवश्यक ज्ञान मिलेगा। आएँ शुरू करें! एंटी-पैटर्न क्या है, इस पर चर्चा करने से पहले, आइए याद करें कि डिज़ाइन पैटर्न क्या है। एक डिजाइन पैटर्नकिसी एप्लिकेशन को डिज़ाइन करते समय उत्पन्न होने वाली सामान्य समस्याओं या स्थितियों के लिए एक दोहराए जाने योग्य वास्तु समाधान है। लेकिन आज हम उनके बारे में बात नहीं कर रहे हैं, बल्कि उनके विपरीत-प्रतिरूपों के बारे में बात कर रहे हैं। आम समस्याओं के एक वर्ग को हल करने के लिए एक विरोधी पैटर्न एक व्यापक लेकिन अप्रभावी, जोखिम भरा और / या अनुत्पादक दृष्टिकोण है। दूसरे शब्दों में, यह गलतियों का एक पैटर्न है (जिसे कभी-कभी ट्रैप भी कहा जाता है)। एक नियम के रूप में, विरोधी पैटर्न निम्न प्रकारों में विभाजित होते हैं:
  1. आर्किटेक्चरल एंटी-पैटर्न - ये एंटी-पैटर्न एक सिस्टम की संरचना के रूप में उत्पन्न होते हैं (आमतौर पर एक आर्किटेक्ट द्वारा)।
  2. प्रबंधन/संगठनात्मक विरोधी पैटर्न - ये परियोजना प्रबंधन में विरोधी पैटर्न हैं, आमतौर पर विभिन्न प्रबंधकों (या प्रबंधकों के समूह) द्वारा सामना किया जाता है।
  3. डेवलपमेंट एंटी-पैटर्न - ये एंटी-पैटर्न तब उत्पन्न होते हैं जब सिस्टम सामान्य प्रोग्रामर द्वारा कार्यान्वित किया जाता है।
विरोधी पैटर्न की पूरी श्रृंखला कहीं अधिक आकर्षक है, लेकिन आज हम उन सभी पर विचार नहीं करेंगे। साधारण डेवलपर्स के लिए, यह बहुत अधिक होगा। शुरुआत करने वालों के लिए, आइए एक उदाहरण के रूप में प्रबंधन विरोधी पैटर्न पर विचार करें।

1. विश्लेषणात्मक पक्षाघात

विश्लेषण पक्षाघातक्लासिक प्रबंधन विरोधी पैटर्न माना जाता है। इसमें नियोजन के दौरान स्थिति का अति-विश्लेषण करना शामिल है, ताकि विकास प्रक्रिया को अनिवार्य रूप से पंगु बनाकर कोई निर्णय या कार्रवाई न की जा सके। यह अक्सर तब होता है जब लक्ष्य पूर्णता प्राप्त करना होता है और विश्लेषण अवधि के दौरान पूरी तरह से सब कुछ पर विचार करना होता है। इस विरोधी पैटर्न को मंडलियों में चलने (एक रन-ऑफ-द-मिल बंद लूप), संशोधित करने और विस्तृत मॉडल बनाने की विशेषता है, जो बदले में वर्कफ़्लो में हस्तक्षेप करता है। उदाहरण के लिए, आप एक स्तर पर चीजों की भविष्यवाणी करने की कोशिश कर रहे हैं: लेकिन क्या होगा यदि कोई उपयोगकर्ता अचानक अपने नाम के चौथे और पांचवें अक्षर के आधार पर कर्मचारियों की एक सूची बनाना चाहता है, जिसमें उन परियोजनाओं की सूची भी शामिल है जिन पर उन्होंने सबसे अधिक काम के घंटे बिताए पिछले चार वर्षों में नए साल और अंतर्राष्ट्रीय महिला दिवस के बीच? संक्षेप में, यह' बहुत अधिक विश्लेषण है। विश्लेषण पक्षाघात से लड़ने के लिए यहां कुछ युक्तियां दी गई हैं:
  1. आपको निर्णय लेने के लिए एक दीर्घकालीन लक्ष्य को एक प्रकाश स्तंभ के रूप में परिभाषित करने की आवश्यकता है, ताकि आपका प्रत्येक निर्णय आपको स्थिर करने के बजाय लक्ष्य के करीब ले जाए।
  2. छोटी-छोटी बातों पर ध्यान केंद्रित न करें (एक महत्वहीन विवरण के बारे में निर्णय क्यों लें जैसे कि यह आपके जीवन का सबसे महत्वपूर्ण निर्णय था?)
  3. निर्णय के लिए एक समय सीमा निर्धारित करें।
  4. किसी काम को पूरी तरह से पूरा करने की कोशिश न करें — बेहतर है कि उसे अच्छी तरह से किया जाए।
यहां बहुत अधिक गहराई में जाने की आवश्यकता नहीं है, इसलिए हम अन्य प्रबंधकीय प्रतिरूपों पर विचार नहीं करेंगे। इसलिए, बिना किसी परिचय के, हम कुछ वास्तुशिल्प विरोधी पैटर्न पर आगे बढ़ेंगे, क्योंकि इस लेख को प्रबंधकों के बजाय भविष्य के डेवलपर्स द्वारा पढ़े जाने की सबसे अधिक संभावना है।

2. ईश्वर वस्तु

एक गॉड ऑब्जेक्ट एक एंटी-पैटर्न है जो सभी प्रकार के कार्यों की अत्यधिक एकाग्रता और बड़ी मात्रा में असमान डेटा (एक वस्तु जिसके चारों ओर घूमता है) का वर्णन करता है। एक छोटा सा उदाहरण लें:

public class SomeUserGodObject {
   private static final String FIND_ALL_USERS_EN = "SELECT id, email, phone, first_name_en, access_counter, middle_name_en, last_name_en, created_date FROM users;
   private static final String FIND_BY_ID = "SELECT id, email, phone, first_name_en, access_counter, middle_name_en, last_name_en, created_date FROM users WHERE id = ?";
   private static final String FIND_ALL_CUSTOMERS = "SELECT id, u.email, u.phone, u.first_name_en, u.middle_name_en, u.last_name_en, u.created_date" +
           "  WHERE u.id IN (SELECT up.user_id FROM user_permissions up WHERE up.permission_id = ?)";
   private static final String FIND_BY_EMAIL = "SELECT id, email, phone, first_name_en, access_counter, middle_name_en, last_name_en, created_dateFROM users WHERE email = ?";
   private static final String LIMIT_OFFSET = " LIMIT ? OFFSET ?";
   private static final String ORDER = " ORDER BY ISNULL(last_name_en), last_name_en, ISNULL(first_name_en), first_name_en, ISNULL(last_name_ru), " +
           "last_name_ru, ISNULL(first_name_ru), first_name_ru";
   private static final String CREATE_USER_EN = "INSERT INTO users(id, phone, email, first_name_en, middle_name_en, last_name_en, created_date) " +
           "VALUES (?, ?, ?, ?, ?, ?, ?)";
   private static final String FIND_ID_BY_LANG_CODE = "SELECT id FROM languages WHERE lang_code = ?";
                                  ........
   private final JdbcTemplate jdbcTemplate;
   private Map<String, String> firstName;
   private Map<String, String> middleName;
   private Map<String, String> lastName;
   private List<Long> permission;
                                   ........
   @Override
   public List<User> findAllEnCustomers(Long permissionId) {
       return jdbcTemplate.query( FIND_ALL_CUSTOMERS + ORDER, userRowMapper(), permissionId);
   }
   @Override
   public List<User> findAllEn() {
       return jdbcTemplate.query(FIND_ALL_USERS_EN + ORDER, userRowMapper());
   }
   @Override
   public Optional<List<User>> findAllEnByEmail(String email) {
       var query = FIND_ALL_USERS_EN + FIND_BY_EMAIL + ORDER;
       return Optional.ofNullable(jdbcTemplate.query(query, userRowMapper(), email));
   }
                              .............
   private List<User> findAllWithoutPageEn(Long permissionId, Type type) {
       switch (type) {
           case USERS:
               return findAllEnUsers(permissionId);
           case CUSTOMERS:
               return findAllEnCustomers(permissionId);
           default:
               return findAllEn();
       }
   }
                              ..............…

   private RowMapper<User> userRowMapperEn() {
       return (rs, rowNum) ->
               User.builder()
                       .id(rs.getLong("id"))
                       .email(rs.getString("email"))
                       .accessFailed(rs.getInt("access_counter"))
                       .createdDate(rs.getObject("created_date", LocalDateTime.class))
                       .firstName(rs.getString("first_name_en"))
                       .middleName(rs.getString("middle_name_en"))
                       .lastName(rs.getString("last_name_en"))
                       .phone(rs.getString("phone"))
                       .build();
   }
}
यहाँ हम एक विशाल वर्ग देखते हैं जो सब कुछ करता है। इसमें डेटाबेस क्वेरीज़ के साथ-साथ कुछ डेटा भी होते हैं। हम FindAllWithoutPageEn Facade मेथड भी देखते हैं, जिसमें बिजनेस लॉजिक शामिल है। ऐसी देव वस्तु उचित रूप से बनाए रखने के लिए विशाल और अजीब हो जाती है। हमें कोड के हर टुकड़े में इसके साथ खिलवाड़ करना होगा। कई सिस्टम घटक इस पर भरोसा करते हैं और इसके साथ कसकर जुड़े होते हैं। ऐसे कोड को बनाए रखना कठिन और कठिन हो जाता है। ऐसे मामलों में, कोड को अलग-अलग वर्गों में विभाजित किया जाना चाहिए, जिनमें से प्रत्येक का केवल एक उद्देश्य होगा। इस उदाहरण में, हम God object को Dao Class में विभाजित कर सकते हैं:

public class UserDaoImpl {
   private static final String FIND_ALL_USERS_EN = "SELECT id, email, phone, first_name_en, access_counter, middle_name_en, last_name_en, created_date FROM users;
   private static final String FIND_BY_ID = "SELECT id, email, phone, first_name_en, access_counter, middle_name_en, last_name_en, created_date FROM users WHERE id = ?";
  
                                   ........
   private final JdbcTemplate jdbcTemplate;
                                                        
                                   ........
   @Override
   public List<User> findAllEnCustomers(Long permissionId) {
       return jdbcTemplate.query(FIND_ALL_CUSTOMERS + ORDER, userRowMapper(), permissionId);
   }
   @Override
   public List<User> findAllEn() {
       return jdbcTemplate.query(FIND_ALL_USERS_EN + ORDER, userRowMapper());
   }
  
                               ........
}
एक वर्ग जिसमें डेटा और डेटा तक पहुँचने के तरीके हैं:

public class UserInfo {
   private Map<String, String> firstName;
                     …..
   public Map<String, String> getFirstName() {
       return firstName;
   }
   public void setFirstName(Map<String, String> firstName) {
       this.firstName = firstName;
   }
                    ....
और व्यापार तर्क के साथ विधि को सेवा में स्थानांतरित करना अधिक उपयुक्त होगा:

private List<User> findAllWithoutPageEn(Long permissionId, Type type) {
   switch (type) {
       case USERS:
           return findAllEnUsers(permissionId);
       case CUSTOMERS:
           return findAllEnCustomers(permissionId);
       default:
           return findAllEn();
   }
}

3. सिंगलटन

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

  2. एक सिंगलटन ठोस सिद्धांतों का उल्लंघन करता है - एकल जिम्मेदारी सिद्धांत: अपने प्रत्यक्ष कर्तव्यों के अलावा, सिंगलटन वर्ग उदाहरणों की संख्या को भी नियंत्रित करता है।

  3. एक साधारण वर्ग की सिंगलटन पर निर्भरता वर्ग के इंटरफ़ेस में दिखाई नहीं देती है। क्योंकि एक सिंगलटन उदाहरण आमतौर पर एक विधि तर्क के रूप में पारित नहीं किया जाता है, लेकिन इसके बजाय सीधे getInstance () के माध्यम से प्राप्त किया जाता है, आपको सिंगलटन पर वर्ग की निर्भरता की पहचान करने के लिए प्रत्येक विधि के कार्यान्वयन में शामिल होने की आवश्यकता है - बस एक वर्ग की जनता को देखते हुए अनुबंध पर्याप्त नहीं है।

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

    दूसरे शब्दों में, एक सिंगलटन युग्मन को बढ़ाता है, और ऊपर वर्णित सब कुछ बढ़े हुए युग्मन के परिणाम से ज्यादा कुछ नहीं है।

    और यदि आप इसके बारे में सोचते हैं, तो आप सिंगलटन का उपयोग करने से बच सकते हैं। उदाहरण के लिए, किसी वस्तु के उदाहरणों की संख्या को नियंत्रित करने के लिए विभिन्न प्रकार के कारखानों का उपयोग करना काफी संभव (और वास्तव में आवश्यक) है।

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

    इस विषय पर अब कई अंतहीन और अपूरणीय बहसें छिड़ी हुई हैं। यह आपको तय करना है कि सिंगलटन एक पैटर्न है या एंटी-पैटर्न।

    हम उस पर टिके नहीं रहेंगे। इसके बजाय, हम आज के अंतिम डिज़ाइन पैटर्न की ओर बढ़ेंगे - पोल्टरजिस्ट।

4. पोल्टरजिस्ट

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

public class UserManager {
   private UserService service;
   public UserManager(UserService userService) {
       service = userService;
   }
   User createUser(User user) {
       return service.create(user);
   }
   Long findAllUsers(){
       return service.findAll().size();
   }
   String findEmailById(Long id) {
       return service.findById(id).getEmail();}
   User findUserByEmail(String email) {
       return service.findByEmail(email);
   }
   User deleteUserById(Long id) {
       return service.delete(id);
   }
}
हमें ऐसी वस्तु की आवश्यकता क्यों है जो सिर्फ एक मध्यस्थ है और अपना काम किसी और को सौंपती है? हम इसे खत्म कर देते हैं और लंबे समय तक रहने वाली वस्तुओं के लिए इसकी थोड़ी सी कार्यक्षमता को स्थानांतरित कर देते हैं। अगला, हम उन पैटर्नों की ओर बढ़ते हैं जो हमारे लिए सबसे अधिक रुचि रखते हैं (साधारण डेवलपर्स के रूप में), यानी विकास विरोधी पैटर्न

5. हार्ड कोडिंग

तो हम इस भयानक शब्द पर पहुंचे हैं: हार्ड कोडिंग। इस एंटी-पैटर्न का सार यह है कि कोड एक विशिष्ट हार्डवेयर कॉन्फ़िगरेशन और/या सिस्टम वातावरण से दृढ़ता से जुड़ा हुआ है। यह कोड को अन्य कॉन्फ़िगरेशन में पोर्ट करना बहुत जटिल करता है। यह एंटी-पैटर्न मैजिक नंबरों के साथ निकटता से जुड़ा हुआ है (ये एंटी-पैटर्न अक्सर आपस में जुड़े होते हैं)। उदाहरण:

public Connection buildConnection() throws Exception {
   Class.forName("com.mysql.cj.jdbc.Driver");
   connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/someDb?characterEncoding=UTF-8&characterSetResults=UTF-8&serverTimezone=UTC", "user01", "12345qwert");
   return connection;
}
दर्द होता है, है ना? यहां हम अपनी कनेक्शन सेटिंग्स को हार्ड कोड करते हैं। नतीजतन, कोड केवल MySQL के साथ ही सही ढंग से काम करेगा। डेटाबेस को बदलने के लिए, हमें कोड में गोता लगाने और सब कुछ मैन्युअल रूप से बदलने की आवश्यकता होगी। कॉन्फ़िगरेशन को एक अलग फ़ाइल में रखना एक अच्छा समाधान होगा:

spring:
  datasource:
    jdbc-url:jdbc:mysql://localhost:3306/someDb?characterEncoding=UTF-8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username:  user01
    password:  12345qwert
एक अन्य विकल्प स्थिरांक का उपयोग करना है।

6. नाव का लंगर

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

public User update(Long id, User request) {
   User user = mergeUser(findById(id), request);
   return userDAO.update(user);
}
private User mergeUser(User findUser, User requestUser) {
   return new User(
           findUser.getId(),
           requestUser.getEmail() != null ? requestUser.getEmail() : findUser.getEmail(),
           requestUser.getFirstName() != null ? requestUser.getFirstName() : findUser.getFirstNameRu(),
           requestUser.getMiddleName() != null ? requestUser.getMiddleName() : findUser.getMiddleNameRu(),
           requestUser.getLastName() != null ? requestUser.getLastName() : findUser.getLastNameEn(),
           requestUser.getPhone() != null ? requestUser.getPhone() : findUser.getPhone());
}
हमारे पास एक अद्यतन विधि है जो डेटाबेस से उपयोगकर्ता डेटा को विधि से पारित उपयोगकर्ता डेटा के साथ विलय करने के लिए एक अलग विधि का उपयोग करती है (यदि उपयोगकर्ता अद्यतन विधि में पास हो गया है तो एक शून्य फ़ील्ड है, तो पुराना फ़ील्ड मान डेटाबेस से लिया जाता है) . फिर मान लीजिए कि एक नई आवश्यकता है कि अभिलेखों को पुराने के साथ विलय नहीं किया जाना चाहिए, बल्कि इसके बजाय, भले ही अशक्त क्षेत्र हों, उनका उपयोग पुराने को अधिलेखित करने के लिए किया जाता है:

public User update(Long id, User request) {
   return userDAO.update(user);
}
इसका मतलब यह है कि मर्जयूजर का अब उपयोग नहीं किया जाता है, लेकिन इसे हटाने के लिए खेद होगा - क्या होगा अगर यह विधि (या इस पद्धति का विचार) किसी दिन काम आ सकती है? ऐसा कोड केवल सिस्टम को जटिल बनाता है और भ्रम का परिचय देता है, अनिवार्य रूप से कोई व्यावहारिक मूल्य नहीं है। हमें यह नहीं भूलना चाहिए कि जब आप किसी अन्य परियोजना के लिए निकलते हैं तो "मृत टुकड़े" वाले ऐसे कोड को किसी सहयोगी को पास करना मुश्किल होगा। नाव एंकरों से निपटने का सबसे अच्छा तरीका कोड को रिफैक्टर करना है, यानी कोड के अनुभागों को हटाएं (दिल तोड़ने वाला, मुझे पता है)। इसके अतिरिक्त, विकास कार्यक्रम तैयार करते समय, ऐसे एंकरों को ध्यान में रखना आवश्यक है (साफ-सफाई के लिए समय आवंटित करना)।

7. ऑब्जेक्ट सेसपूल

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

class ReusablePool {
   private static ReusablePool pool;
   private List<Resource> list = new LinkedList<>();
   private ReusablePool() {
       for (int i = 0; i < 3; i++)
           list.add(new Resource());
   }
   public static ReusablePool getInstance() {
       if (pool == null) {
           pool = new ReusablePool();
       }
       return pool;
   }
   public Resource acquireResource() {
       if (list.size() == 0) {
           return new Resource();
       } else {
           Resource r = list.get(0);
           list.remove(r);
           return r;
       }
   }
   public void releaseResource(Resource r) {
       list.add(r);
   }
}
इस वर्ग को उपरोक्त सिंगलटन पैटर्न/एंटी-पैटर्न के रूप में प्रस्तुत किया गया है , अर्थात इस प्रकार की केवल एक ही वस्तु हो सकती है। यह कुछ Resourceवस्तुओं का उपयोग करता है। डिफ़ॉल्ट रूप से, कंस्ट्रक्टर पूल को 4 उदाहरणों से भरता है। जब आप कोई वस्तु प्राप्त करते हैं, तो उसे पूल से हटा दिया जाता है (यदि कोई उपलब्ध वस्तु नहीं है, तो एक बनाई जाती है और तुरंत वापस आ जाती है)। और अंत में, हमारे पास वस्तु को वापस रखने का एक तरीका है। संसाधन वस्तुएं इस तरह दिखती हैं:

public class Resource {
   private Map<String, String> patterns;
   public Resource() {
       patterns = new HashMap<>();
       patterns.put("proxy", "https://en.wikipedia.org/wiki/Proxy_pattern");
       patterns.put("bridge", "https://en.wikipedia.org/wiki/Bridge_pattern");
       patterns.put("facade", "https://en.wikipedia.org/wiki/Facade_pattern");
       patterns.put("builder", "https://en.wikipedia.org/wiki/Builder_pattern");
   }
   public Map<String, String> getPatterns() {
       return patterns;
   }
   public void setPatterns(Map<String, String> patterns) {
       this.patterns = patterns;
   }
}
यहां हमारे पास एक छोटी सी वस्तु है जिसमें कुंजी के रूप में डिजाइन पैटर्न नाम के साथ एक नक्शा है और मूल्य के रूप में संबंधित विकिपीडिया लिंक, साथ ही मानचित्र तक पहुंचने के तरीके भी हैं। आइए मुख्य पर एक नज़र डालें:

class SomeMain {
   public static void main(String[] args) {
       ReusablePool pool = ReusablePool.getInstance();

       Resource firstResource = pool.acquireResource();
       Map<String, String> firstPatterns = firstResource.getPatterns();
       // use our map somehow...
       pool.releaseResource(firstResource);

       Resource secondResource = pool.acquireResource();
       Map<String, String> secondPatterns = firstResource.getPatterns();
       // use our map somehow...
       pool.releaseResource(secondResource);

       Resource thirdResource = pool.acquireResource();
       Map<String, String> thirdPatterns = firstResource.getPatterns();
       // use our map somehow...
       pool.releaseResource(thirdResource);
   }
}
यहां सब कुछ पर्याप्त स्पष्ट है: हमें एक पूल ऑब्जेक्ट मिलता है, पूल से संसाधनों के साथ एक ऑब्जेक्ट प्राप्त होता है, रिसोर्स ऑब्जेक्ट से मैप प्राप्त होता है, इसके साथ कुछ करें, और आगे के पुन: उपयोग के लिए यह सब पूल में इसके स्थान पर रख दें। वोइला, यह ऑब्जेक्ट पूल डिज़ाइन पैटर्न है। लेकिन हम एंटी-पैटर्न के बारे में बात कर रहे थे, है ना? मुख्य विधि में निम्नलिखित मामले पर विचार करें:

Resource fourthResource = pool.acquireResource();
   Map<String, String> fourthPatterns = firstResource.getPatterns();
// use our map somehow...
fourthPatterns.clear();
firstPatterns.put("first","blablabla");
firstPatterns.put("second","blablabla");
firstPatterns.put("third","blablabla");
firstPatterns.put("fourth","blablabla");
pool.releaseResource(fourthResource);
यहाँ, फिर से, हमें एक रिसोर्स ऑब्जेक्ट मिलता है, हमें इसके पैटर्न का नक्शा मिलता है, और हम मैप के साथ कुछ करते हैं। लेकिन मानचित्र को वस्तुओं के पूल में वापस सहेजने से पहले, इसे साफ़ कर दिया जाता है और फिर दूषित डेटा से भर दिया जाता है, जिससे संसाधन वस्तु पुन: उपयोग के लिए अनुपयुक्त हो जाती है। ऑब्जेक्ट पूल के मुख्य विवरणों में से एक यह है कि जब कोई ऑब्जेक्ट वापस किया जाता है, तो उसे पुन: उपयोग के लिए उपयुक्त स्थिति में पुनर्स्थापित करना होगा। यदि पूल में लौटाई गई वस्तुएं गलत या अपरिभाषित स्थिति में रहती हैं, तो हमारे डिजाइन को ऑब्जेक्ट सेसपूल कहा जाता है। क्या उन वस्तुओं को स्टोर करने का कोई अर्थ है जो पुन: उपयोग के लिए उपयुक्त नहीं हैं? इस स्थिति में, हम कंस्ट्रक्टर में आंतरिक मानचित्र को अपरिवर्तनीय बना सकते हैं:

public Resource() {
   patterns = new HashMap<>();
   patterns.put("proxy", "https://en.wikipedia.org/wiki/Proxy_pattern");
   patterns.put("bridge", "https://en.wikipedia.org/wiki/Bridge_pattern");
   patterns.put("facade", "https://en.wikipedia.org/wiki/Facade_pattern");
   patterns.put("builder", "https://en.wikipedia.org/wiki/Builder_pattern");
   patterns = Collections.unmodifiableMap(patterns);
}
मैप की सामग्री को बदलने की कोशिशें और इच्छाएँ मिट जाएँगी, उनके द्वारा जनरेट किए गए UnsupportedOperationException के कारण धन्यवाद। एंटी-पैटर्न जाल हैं जो डेवलपर्स को समय की तीव्र कमी, लापरवाही, अनुभवहीनता या परियोजना प्रबंधकों के दबाव के कारण अक्सर सामना करना पड़ता है। हड़बड़ी करना, जो सामान्य है, भविष्य में आवेदन के लिए बड़ी समस्याएँ पैदा कर सकता है, इसलिए आपको इन त्रुटियों के बारे में पहले से पता होना चाहिए और उनसे बचना चाहिए। यह लेख के पहले भाग को समाप्त करता है। करने के लिए जारी...
टिप्पणियां
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION