CodeGym /Java Blog /यादृच्छिक /विरोधी नमुने काय आहेत? चला काही उदाहरणे पाहू (भाग १)
John Squirrels
पातळी 41
San Francisco

विरोधी नमुने काय आहेत? चला काही उदाहरणे पाहू (भाग १)

यादृच्छिक या ग्रुपमध्ये प्रकाशित केले
सर्वांना शुभ दिवस! दुसऱ्या दिवशी माझी नोकरीची मुलाखत होती, आणि मला अँटी-पॅटर्नबद्दल काही प्रश्न विचारण्यात आले: ते काय आहेत, कोणते प्रकार आहेत आणि कोणती व्यावहारिक उदाहरणे आहेत. अर्थात, मी या प्रश्नाचे उत्तर दिले, परंतु अगदी वरवरचे, कारण मी यापूर्वी या विषयात खोलवर गेले नव्हते. मुलाखतीनंतर, मी इंटरनेट चाळायला सुरुवात केली आणि या विषयात मी अधिकाधिक मग्न झालो. विरोधी नमुने काय आहेत?  चला काही उदाहरणे पाहू (भाग १) - १ आज मी सर्वात लोकप्रिय अँटी-पॅटर्नचे संक्षिप्त विहंगावलोकन देऊ इच्छितो आणि काही उदाहरणांचे पुनरावलोकन करू इच्छितो. मला आशा आहे की हे वाचून तुम्हाला या क्षेत्रात आवश्यक असलेले ज्ञान मिळेल. चला सुरू करुया! अँटी-पॅटर्न म्हणजे काय यावर चर्चा करण्यापूर्वी, डिझाइन पॅटर्न म्हणजे काय ते आठवूया. एक डिझाइन नमुनाअॅप्लिकेशन डिझाइन करताना उद्भवणाऱ्या सामान्य समस्या किंवा परिस्थितींसाठी पुनरावृत्ती करण्यायोग्य आर्किटेक्चरल उपाय आहे. परंतु आज आपण त्यांच्याबद्दल बोलत नाही, तर त्यांचे विरुद्ध - विरोधी नमुने बोलत आहोत. अँटी -पॅटर्न हा एक व्यापक परंतु अप्रभावी, धोकादायक आणि/किंवा सामान्य समस्यांचे निराकरण करण्यासाठी अनुत्पादक दृष्टीकोन आहे. दुसऱ्या शब्दांत, हा चुकांचा नमुना आहे (कधीकधी सापळा देखील म्हटले जाते). नियमानुसार, विरोधी नमुने खालील प्रकारांमध्ये विभागलेले आहेत:
  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 दर्शनी पद्धत देखील पाहतो, ज्यामध्ये व्यवसाय तर्क समाविष्ट आहे. अशी देव वस्तू योग्यरित्या राखण्यासाठी प्रचंड आणि अस्ताव्यस्त बनते. कोडच्या प्रत्येक तुकड्यात आपल्याला त्याच्याशी गोंधळ करावा लागेल. सिस्टमचे बरेच घटक त्यावर अवलंबून असतात आणि त्याच्याशी घट्ट जोडलेले असतात. अशी संहिता राखणे कठीण होत जाते. अशा प्रकरणांमध्ये, कोड स्वतंत्र वर्गांमध्ये विभागला गेला पाहिजे, ज्यापैकी प्रत्येकाचा एकच उद्देश असेल. या उदाहरणात, आपण देव ऑब्जेक्टला डाओ वर्गात विभाजित करू शकतो:

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() द्वारे प्राप्त केले जाते, सिंगलटनवर वर्गाचे अवलंबित्व ओळखण्यासाठी तुम्हाला प्रत्येक पद्धतीच्या अंमलबजावणीमध्ये प्रवेश करणे आवश्यक आहे — फक्त वर्गाच्या लोकांकडे पाहणे करार पुरेसे नाही.

    सिंगलटनची उपस्थिती संपूर्णपणे अनुप्रयोगाची चाचणीक्षमता आणि विशेषतः सिंगलटन वापरणारे वर्ग कमी करते. सर्वप्रथम, तुम्ही सिंगलटनला मॉक ऑब्जेक्टसह बदलू शकत नाही. दुसरे, सिंगलटनमध्ये त्याची स्थिती बदलण्यासाठी इंटरफेस असल्यास, चाचण्या एकमेकांवर अवलंबून असतील.

    दुस-या शब्दात सांगायचे तर, सिंगलटन कपलिंग वाढवते, आणि वर नमूद केलेली प्रत्येक गोष्ट वाढलेल्या कपलिंगच्या परिणामापेक्षा काहीच नाही.

    आणि आपण याबद्दल विचार केल्यास, आपण सिंगलटन वापरणे टाळू शकता. उदाहरणार्थ, एखाद्या वस्तूच्या घटनांची संख्या नियंत्रित करण्यासाठी विविध प्रकारचे कारखाने वापरणे शक्य आहे (आणि खरोखर आवश्यक आहे).

    सिंगलटनवर आधारित संपूर्ण ऍप्लिकेशन आर्किटेक्चर तयार करण्याच्या प्रयत्नात सर्वात मोठा धोका आहे. या दृष्टिकोनासाठी बरेच आश्चर्यकारक पर्याय आहेत. सर्वात महत्वाचे उदाहरण म्हणजे स्प्रिंग, म्हणजे त्याचे IoC कंटेनर: ते सेवांच्या निर्मितीवर नियंत्रण ठेवण्याच्या समस्येचे नैसर्गिक समाधान आहेत, कारण ते प्रत्यक्षात "स्टिरॉइड्सचे कारखाने" आहेत.

    या विषयावर आता अनेक न संपणारे आणि न जुळणारे वादविवाद सुरू आहेत. सिंगलटन पॅटर्न आहे की अँटी-पॅटर्न आहे हे ठरवणे तुमच्यावर अवलंबून आहे.

    आम्ही त्यावर रेंगाळणार नाही. त्याऐवजी, आम्ही आजच्या शेवटच्या डिझाइन पॅटर्नकडे जाऊ - poltergeist.

4. Poltergeist

पोल्टर्जिस्ट हा एक अर्थहीन वर्गाचा समावेश असलेला अँटी-पॅटर्न आहे जो दुसर्‍या वर्गाच्या पद्धती कॉल करण्यासाठी वापरला जातो किंवा फक्त अमूर्ततेचा अनावश्यक स्तर जोडतो . हे अँटी-पॅटर्न स्वतःला अल्पायुषी वस्तू म्हणून प्रकट करते, अवस्थेशिवाय. या ऑब्जेक्ट्सचा वापर इतर, अधिक कायमस्वरूपी ऑब्जेक्ट सुरू करण्यासाठी केला जातो.

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);
}
याचा अर्थ असा की mergeUser यापुढे वापरला जाणार नाही, परंतु तो हटवणे खेदजनक आहे — ही पद्धत (किंवा या पद्धतीची कल्पना) एखाद्या दिवशी उपयोगी पडली तर? असा कोड केवळ प्रणालींना गुंतागुंतीचा बनवतो आणि गोंधळ निर्माण करतो, मूलत: कोणतेही व्यावहारिक मूल्य नसते. आपण हे विसरू नये की "मृत तुकड्यांसह" असा कोड जेव्हा आपण दुसर्या प्रकल्पासाठी निघता तेव्हा सहकाऱ्याला पास करणे कठीण होईल. बोट अँकरचा सामना करण्याचा सर्वोत्तम मार्ग म्हणजे कोड रिफॅक्टर करणे, म्हणजे कोडचे विभाग हटवणे (हृदयद्रावक, मला माहित आहे). याव्यतिरिक्त, विकासाचे वेळापत्रक तयार करताना, अशा अँकरचा हिशेब ठेवणे आवश्यक आहे (नीटनेटके करण्यासाठी वेळ वाटप करण्यासाठी).

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