అందరికీ శుభదినం! మరొక రోజు నాకు ఉద్యోగ ఇంటర్వ్యూ ఉంది మరియు యాంటీ-ప్యాటర్న్‌ల గురించి నన్ను కొన్ని ప్రశ్నలు అడిగారు: అవి ఏమిటి, ఏ రకాలు ఉన్నాయి మరియు ఏ ఆచరణాత్మక ఉదాహరణలు ఉన్నాయి. వాస్తవానికి, నేను ప్రశ్నకు సమాధానం ఇచ్చాను, కానీ చాలా ఉపరితలంగా, నేను ఇంతకు ముందు ఈ అంశంపై లోతుగా డైవ్ చేయలేదు. ఇంటర్వ్యూ తర్వాత, నేను ఇంటర్నెట్‌ను శోధించడం ప్రారంభించాను మరియు టాపిక్‌లో మరింత ఎక్కువగా మునిగిపోయాను. వ్యతిరేక నమూనాలు ఏమిటి?  కొన్ని ఉదాహరణలు (పార్ట్ 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 ముఖభాగం పద్ధతిని కూడా చూస్తాము, ఇందులో వ్యాపార తర్కం ఉంటుంది. అటువంటి దేవుని వస్తువు అపారమైనది మరియు సరిగ్గా నిర్వహించడానికి ఇబ్బందికరంగా మారుతుంది. ప్రతి కోడ్‌లో మనం దానితో గందరగోళం చెందాలి. అనేక సిస్టమ్ భాగాలు దానిపై ఆధారపడతాయి మరియు దానితో గట్టిగా జతచేయబడతాయి. అటువంటి కోడ్‌ను నిర్వహించడం కష్టం మరియు కష్టం అవుతుంది. అటువంటి సందర్భాలలో, కోడ్ ప్రత్యేక తరగతులుగా విభజించబడాలి, వీటిలో ప్రతి ఒక్కటి ఒక ప్రయోజనం మాత్రమే కలిగి ఉంటుంది. ఈ ఉదాహరణలో, మనం దేవుని వస్తువును డావో తరగతిగా విభజించవచ్చు:

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. సింగిల్టన్ SOLID సూత్రాలను ఉల్లంఘిస్తుంది — ఒకే బాధ్యత సూత్రం: దాని ప్రత్యక్ష విధులతో పాటు, సింగిల్టన్ తరగతి కూడా సందర్భాల సంఖ్యను నియంత్రిస్తుంది.

  3. ఒక సాధారణ తరగతి సింగిల్‌టన్‌పై ఆధారపడటం తరగతి ఇంటర్‌ఫేస్‌లో కనిపించదు. సింగిల్‌టన్ ఉదాహరణ సాధారణంగా మెథడ్ ఆర్గ్యుమెంట్‌గా పాస్ చేయబడదు, బదులుగా నేరుగా getInstance() ద్వారా పొందబడుతుంది కాబట్టి, సింగిల్‌టన్‌పై తరగతి ఆధారపడటాన్ని గుర్తించడానికి మీరు ప్రతి పద్ధతిని అమలులోకి తీసుకురావాలి — కేవలం ఒక తరగతి పబ్లిక్‌ని చూడటం ఒప్పందం సరిపోదు.

    సింగిల్‌టన్ యొక్క ఉనికి మొత్తం అప్లికేషన్ యొక్క టెస్టబిలిటీని మరియు ప్రత్యేకంగా సింగిల్‌టన్‌ని ఉపయోగించే తరగతులను తగ్గిస్తుంది. అన్నింటిలో మొదటిది, మీరు సింగిల్‌టన్‌ను మాక్ ఆబ్జెక్ట్‌తో భర్తీ చేయలేరు. రెండవది, ఒక సింగిల్‌టన్‌కు దాని స్థితిని మార్చడానికి ఇంటర్‌ఫేస్ ఉంటే, అప్పుడు పరీక్షలు ఒకదానిపై ఒకటి ఆధారపడి ఉంటాయి.

    మరో మాటలో చెప్పాలంటే, సింగిల్‌టన్ కలపడాన్ని పెంచుతుంది మరియు పైన పేర్కొన్న ప్రతిదీ పెరిగిన కలపడం యొక్క పరిణామం తప్ప మరేమీ కాదు.

    మరియు మీరు దాని గురించి ఆలోచిస్తే, మీరు సింగిల్‌టన్‌ని ఉపయోగించకుండా నివారించవచ్చు. ఉదాహరణకు, ఒక వస్తువు యొక్క ఉదాహరణల సంఖ్యను నియంత్రించడానికి వివిధ రకాల కర్మాగారాలను ఉపయోగించడం చాలా సాధ్యమే (మరియు వాస్తవానికి అవసరం).

    సింగిల్‌టన్‌ల ఆధారంగా మొత్తం అప్లికేషన్ ఆర్కిటెక్చర్‌ను రూపొందించే ప్రయత్నంలో అతిపెద్ద ప్రమాదం ఉంది. ఈ విధానానికి టన్నుల కొద్దీ అద్భుతమైన ప్రత్యామ్నాయాలు ఉన్నాయి. అత్యంత ముఖ్యమైన ఉదాహరణ స్ప్రింగ్, అవి దాని IoC కంటైనర్లు: అవి వాస్తవానికి "స్టెరాయిడ్‌లపై కర్మాగారాలు" అయినందున, సేవల సృష్టిని నియంత్రించే సమస్యకు సహజ పరిష్కారం.

    ఈ అంశంపై ఇప్పుడు అనేక అంతులేని మరియు సరిదిద్దలేని చర్చలు జరుగుతున్నాయి. సింగిల్‌టన్ ఒక నమూనా లేదా వ్యతిరేక నమూనా కాదా అనేది నిర్ణయించుకోవడం మీ ఇష్టం.

    మేము దానిపై ఆలస్యం చేయము. బదులుగా, మేము ఈ రోజు చివరి డిజైన్ నమూనాకు వెళ్తాము - పోల్టర్జిస్ట్.

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);
}
దీనర్థం 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);
   }
}
ఇక్కడ ప్రతిదీ తగినంత స్పష్టంగా ఉంది: మేము ఒక పూల్ ఆబ్జెక్ట్‌ను పొందుతాము, పూల్ నుండి వనరులతో ఒక వస్తువును పొందుతాము, రిసోర్స్ ఆబ్జెక్ట్ నుండి మ్యాప్‌ను పొందండి, దానితో ఏదైనా చేయండి మరియు తదుపరి పునర్వినియోగం కోసం పూల్‌లో ఇవన్నీ ఉంచండి. Voila, ఇది ఆబ్జెక్ట్ పూల్ డిజైన్ నమూనా. కానీ మేము వ్యతిరేక నమూనాల గురించి మాట్లాడుతున్నాము, సరియైనదా? ప్రధాన పద్ధతిలో కింది కేసును పరిశీలిద్దాం:

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);
}
ప్రయత్నాలు మరియు మ్యాప్ యొక్క కంటెంట్‌లను మార్చాలనే కోరిక అవి సృష్టించే మద్దతు లేని ఆపరేషన్ ఎక్సెప్షన్‌కు ధన్యవాదాలు. యాంటీ-ప్యాటర్న్‌లు అనేది డెవలపర్‌లకు తీవ్రమైన సమయం లేకపోవడం, అజాగ్రత్త, అనుభవం లేకపోవడం లేదా ప్రాజెక్ట్ మేనేజర్‌ల ఒత్తిడి కారణంగా తరచుగా ఎదుర్కొనే ఉచ్చులు. రషింగ్, ఇది సాధారణమైనది, భవిష్యత్తులో అప్లికేషన్ కోసం పెద్ద సమస్యలకు దారి తీస్తుంది, కాబట్టి మీరు ఈ లోపాల గురించి తెలుసుకోవాలి మరియు ముందుగానే వాటిని నివారించాలి. ఇది వ్యాసం యొక్క మొదటి భాగాన్ని ముగించింది. కొనసాగుతుంది...