JavaRush /جاوا بلاگ /Random-UR /اینٹی پیٹرن کیا ہیں؟ آئیے مثالیں دیکھیں (حصہ 1)

اینٹی پیٹرن کیا ہیں؟ آئیے مثالیں دیکھیں (حصہ 1)

گروپ میں شائع ہوا۔
اینٹی پیٹرن کیا ہیں؟  آئیے مثالیں دیکھیں (حصہ 1) - 1سب کو اچھا دن! دوسرے دن میرا انٹرویو ہوا، اور مجھ سے اینٹی پیٹرن کے بارے میں ایک سوال پوچھا گیا: یہ کس قسم کا حیوان ہے، ان کی اقسام اور عملی طور پر کیا مثالیں ہیں۔ بے شک، میں نے اس سوال کا جواب دیا، لیکن انتہائی سطحی طور پر، کیونکہ میں اس مسئلے کے مطالعہ میں زیادہ گہرائی میں نہیں گیا تھا۔ انٹرویو کے بعد، میں نے انٹرنیٹ کو چھیڑنا شروع کیا، اور اس موضوع میں مزید ڈوبتا گیا۔ آج میں سب سے مشہور اینٹی پیٹرن اور ان کی مثالوں کا ایک مختصر جائزہ لینا چاہوں گا، جسے پڑھ کر آپ کو اس مسئلے پر ضروری معلومات مل سکتی ہیں۔ آو شروع کریں! لہذا، اینٹی پیٹرن کیا ہے اس پر بحث کرنے سے پہلے، آئیے یاد رکھیں کہ پیٹرن کیا ہے۔ ایک پیٹرن عام مسائل یا حالات کو حل کرنے کے لیے ایک قابل اعادہ آرکیٹیکچرل ڈیزائن ہے جو ایپلی کیشن کو ڈیزائن کرتے وقت پیدا ہوتا ہے۔ لیکن آج ہم ان کے بارے میں بات نہیں کر رہے ہیں، لیکن ان کے مخالف - مخالف پیٹرن کے بارے میں. ایک اینٹی پیٹرن عام طور پر درپیش مسائل کے ایک طبقے کو حل کرنے کا ایک عام طریقہ ہے جو غیر موثر، خطرناک، یا غیر پیداواری ہے۔ دوسرے لفظوں میں، یہ ایک غلطی کا نمونہ ہے (جسے کبھی کبھی ٹریپ بھی کہا جاتا ہے)۔ اینٹی پیٹرن کیا ہیں؟  آئیے مثالیں دیکھیں (حصہ 1) - 2ایک اصول کے طور پر، antipatterns مندرجہ ذیل اقسام میں تقسیم کیا جاتا ہے:
  1. آرکیٹیکچرل اینٹی پیٹرن - آرکیٹیکچرل اینٹی پیٹرن جو نظام کے ڈھانچے کو ڈیزائن کرتے وقت پیدا ہوتے ہیں (عام طور پر ایک معمار کے ذریعہ)۔
  2. مینجمنٹ اینٹی پیٹرن - مینجمنٹ کے میدان میں اینٹی پیٹرن، جو عام طور پر مختلف مینیجرز (یا مینیجرز کے گروپوں) کو سامنا کرنا پڑتا ہے.
  3. ڈیولپمنٹ اینٹی پیٹرن - اینٹی پیٹرن ترقی کے مسائل ہیں جو اس وقت پیدا ہوتے ہیں جب عام پروگرامرز سسٹم لکھتے ہیں۔
اینٹی پیٹرنز کی خارجیت بہت وسیع ہے، لیکن ہم آج ان پر غور نہیں کریں گے، کیونکہ عام ڈویلپرز کے لیے یہ بہت زیادہ ہوگا۔ کے ساتھ شروع کرنے کے لئے، چلو انتظام کے میدان میں ایک antipattern کی ایک مثال لیتے ہیں.

1. تجزیاتی فالج

تجزیہ فالج کو ایک کلاسک تنظیمی مخالف پیٹرن سمجھا جاتا ہے۔ اس میں منصوبہ بندی کرتے وقت صورتحال کا زیادہ تجزیہ کرنا شامل ہے تاکہ کوئی فیصلہ یا اقدام نہ کیا جائے، بنیادی طور پر ترقی کو مفلوج کر دیتا ہے۔ یہ اکثر اس وقت ہوتا ہے جب مقصد کمال حاصل کرنا اور تجزیہ کی مدت کی مکمل تکمیل کرنا ہوتا ہے۔ اس اینٹی پیٹرن کی خصوصیت دائروں میں چلنا (ایک قسم کا بند لوپ) ہے، تفصیلی ماڈلز پر نظرثانی اور تخلیق کرنا، جس کے نتیجے میں ورک فلو میں مداخلت ہوتی ہے۔ مثال کے طور پر، آپ ان چیزوں کی پیش گوئی کرنے کی کوشش کر رہے ہیں جیسے: کیا ہوگا اگر صارف اچانک اپنے نام کے چوتھے اور پانچویں حروف کی بنیاد پر ملازمین کی فہرست بنانا چاہتا ہے، جس میں اس فہرست میں وہ پروجیکٹ بھی شامل ہیں جن کے لیے انہوں نے کام کے اوقات کے درمیان سب سے زیادہ وقت وقف کیا تھا۔ پچھلے چار سالوں میں نیا سال اور آٹھ مارچ؟ جوہر میں، یہ تجزیہ کی کثرت ہے. حقیقی زندگی کی ایک اچھی مثال یہ ہے کہ کس طرح تجزیہ فالج نے Kodak کو دیوالیہ ہونے تک پہنچایا ۔ تجزیہ فالج کا مقابلہ کرنے کے لیے یہاں چند چھوٹی تجاویز ہیں:
  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) - 3آئیے اس سانچے کے نقصانات کو دیکھتے ہیں:
  1. عالمی ریاست۔ جب ہم کسی کلاس کی مثال تک رسائی حاصل کرتے ہیں، تو ہم نہیں جانتے کہ اس کلاس کی موجودہ حالت کیا ہے یا اسے کس نے تبدیل کیا ہے یا کب، اور وہ حالت وہ نہیں ہو سکتی جس کی ہم توقع کرتے ہیں۔ دوسرے لفظوں میں، سنگلٹن کے ساتھ کام کرنے کی درستگی کا انحصار اس پر کال کرنے کی ترتیب پر ہوتا ہے، جس کی وجہ سے ذیلی نظام ایک دوسرے پر منحصر ہوتے ہیں اور اس کے نتیجے میں، سنجیدگی سے ترقی کی پیچیدگی میں اضافہ ہوتا ہے۔

  2. سنگلٹن SOLID اصولوں میں سے ایک کی خلاف ورزی کرتا ہے - واحد ذمہ داری کا اصول - سنگلٹن کلاس، اپنی فوری ذمہ داریوں کو انجام دینے کے علاوہ، اپنی مثالوں کی تعداد کو بھی کنٹرول کرتی ہے۔

  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);
   }
}
ہمیں ایسی چیز کی ضرورت کیوں ہے جو صرف ایک ثالث ہو اور اپنا کام کسی اور کو سونپے؟ ہم اسے حذف کرتے ہیں، اور چھوٹی فعالیت کو منتقل کرتے ہیں جسے یہ طویل المدتی اشیاء میں لاگو کرتا ہے۔ اس کے بعد، ہم ان نمونوں کی طرف بڑھتے ہیں جو ہمارے لیے سب سے زیادہ دلچسپی رکھتے ہیں (بطور عام ڈویلپر) - develop antipatterns ۔

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. کشتی کا لنگر

اینٹی پیٹرنز کے تناظر میں کشتی کے لنگر کا مطلب ہے کسی ایسے سسٹم کے غیر استعمال شدہ حصوں کو ذخیرہ کرنا جو کچھ اصلاح یا ری فیکٹرنگ کے بعد رہ جاتے ہیں۔ اس کے علاوہ، کوڈ کے کچھ حصوں کو "مستقبل کے لیے" چھوڑا جا سکتا ہے، اگر آپ کو انہیں دوبارہ استعمال کرنا پڑے۔ یہ بنیادی طور پر کوڈ کو ردی کی ٹوکری میں بدل دیتا ہے۔ اینٹی پیٹرن کیا ہیں؟  آئیے مثالیں دیکھیں (حصہ 1) - 4مثال:
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 کاپیوں سے بھرا ہوتا ہے۔ جب ایسی کوئی چیز لی جاتی ہے تو اسے تالاب سے ہٹا دیا جاتا ہے (اگر یہ موجود نہ ہو تو اسے بنایا جاتا ہے اور فوراً دے دیا جاتا ہے) اور آخر میں اس چیز کو واپس رکھنے کا طریقہ موجود ہے۔ اشیاء Resourceاس طرح نظر آتی ہیں:
public class Resource {
   private Map<String, String> patterns;
   public Resource() {
       patterns = new HashMap<>();
       patterns.put("заместитель", "https://studfile.net/preview/3676297/page:3/");
       patterns.put("мост", "https://studfile.net/preview/3676297/page:4/");
       patterns.put("фасад", "https://studfile.net/preview/3676297/page:5/");
       patterns.put("строитель", "https://studfile.net/preview/3676297/page:6/#16");
   }
   public Map<String, String> getPatterns() {
       return patterns;
   }
   public void setPatterns(Map<String, String> patterns) {
       this.patterns = patterns;
   }
}
یہاں ہمارے پاس ایک چھوٹی چیز ہے جس میں ایک نقشہ ہے جس میں پیٹرن کے نام کلید کے طور پر ہیں اور قیمت کے طور پر ان کے لنکس کے ساتھ ساتھ نقشے تک رسائی کے طریقے ہیں۔ آئیں دیکھیں main:
class SomeMain {
   public static void main(String[] args) {
       ReusablePool pool = ReusablePool.getInstance();

       Resource firstResource = pool.acquireResource();
       Map<String, String> firstPatterns = firstResource.getPatterns();
       // ......Howим-то образом используем нашу мапу.....
       pool.releaseResource(firstResource);

       Resource secondResource = pool.acquireResource();
       Map<String, String> secondPatterns = firstResource.getPatterns();
       // ......Howим-то образом используем нашу мапу.....
       pool.releaseResource(secondResource);

       Resource thirdResource = pool.acquireResource();
       Map<String, String> thirdPatterns = firstResource.getPatterns();
       // ......Howим-то образом используем нашу мапу.....
       pool.releaseResource(thirdResource);
   }
}
یہاں سب کچھ بھی واضح ہے: ہم ایک پول آبجیکٹ لیتے ہیں، اس سے وسائل کے ساتھ کسی چیز کو نکالتے ہیں، اس سے نقشہ لیتے ہیں، اس کے ساتھ کچھ کرتے ہیں اور اسے دوبارہ استعمال کے لیے دوبارہ پول میں ڈال دیتے ہیں۔ Voila: یہاں آپ کے پاس آبجیکٹ پول پیٹرن ہے۔ لیکن ہم اینٹی پیٹرن کے بارے میں بات کر رہے تھے، کیا ہم نہیں تھے؟ آئیے اس کیس کو دیکھتے ہیں main:
Resource fourthResource = pool.acquireResource();
   Map<String, String> fourthPatterns = firstResource.getPatterns();
// ......Howим-то образом используем нашу мапу.....
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("заместитель", "https://studfile.net/preview/3676297/page:3/");
   patterns.put("мост", "https://studfile.net/preview/3676297/page:4/");
   patterns.put("фасад", "https://studfile.net/preview/3676297/page:5/");
   patterns.put("строитель", "https://studfile.net/preview/3676297/page:6/#16");
   patterns = Collections.unmodifiableMap(patterns);
}
(مواد کو تبدیل کرنے کی کوششیں اور خواہش UnsupportedOperationException کے ساتھ گر جائے گی)۔ اینٹی پیٹرن ایسے جال ہیں جن میں ڈویلپر اکثر وقت کی شدید کمی، عدم توجہی، ناتجربہ کاری، یا مینیجرز کی طرف سے کک کی وجہ سے پھنس جاتے ہیں۔ وقت کی معمول کی کمی اور جلد بازی کا نتیجہ مستقبل میں درخواست کے لیے بڑی پریشانیوں کا باعث بن سکتا ہے، اس لیے ان غلطیوں کو پہلے سے جاننا اور ان سے بچنے کی ضرورت ہے۔ اینٹی پیٹرن کیا ہیں؟  آئیے مثالیں دیکھیں (حصہ 1) - 6اس کے ساتھ مضمون کا پہلا حصہ ختم ہو گیا ہے: جاری رکھا جائے گا ۔
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION