JavaRush /جاوا بلاگ /Random-UR /اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟

اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟

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

مسئلہ کے بارے میں مزید تفصیلات

سب سے پہلے، آئیے پرانے نظام کے رویے کی نقل کرتے ہیں۔ ہم کہتے ہیں کہ یہ کام یا اسکول میں دیر ہونے کی وجوہات پیدا کرتا ہے۔ ایسا کرنے کے لیے، ہمارے پاس ایک انٹرفیس ہے Excuseجس میں طریقے ہیں generateExcuse()، likeExcuse()اور dislikeExcuse()۔
public interface Excuse {
   String generateExcuse();
   void likeExcuse(String excuse);
   void dislikeExcuse(String excuse);
}
یہ انٹرفیس کلاس کے ذریعہ لاگو کیا جاتا ہے WorkExcuse:
public class WorkExcuse implements Excuse {
   private String[] reasonOptions = {"по невероятному стечению обстоятельств у нас в доме закончилась горячая вода и я ждал, пока солнечный свет, сконцентрированный через лупу, нагреет кружку воды, чтобы я мог умыться.",
   "искусственный интеллект в моем будильнике подвел меня и разбудил на час раньше обычного. Поскольку сейчас зима, я думал что еще ночь и уснул. Дальше все How в тумане.",
   "предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице."};
   private String[] sorryOptions = {"Это, конечно, не повторится, мне очень жаль.", "Прошу меня извинить за непрофессиональное поведение.", "Нет оправдания моему поступку. Я недостоин этой должности."};

   @Override
   public String generateExcuse() { // Случайно выбираем отговорку из массива
       String result = "Я сегодня опоздал, потому что " + reasonOptions[(int) Math.round(Math.random() + 1)] + "\n" +
               sorryOptions[(int) Math.round(Math.random() + 1)];
       return result;
   }

   @Override
   public void likeExcuse(String excuse) {
       // Дублируем элемент в массиве, чтобы шанс его выпадения был выше
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Удаляем элемент из массива
   }
}
آئیے مثال کی جانچ کریں:
Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
نتیجہ:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице. 
Прошу меня извинить за непрофессиональное поведение.
اب تصور کریں کہ آپ نے سروس شروع کی، اعداد و شمار جمع کیے اور دیکھا کہ سروس استعمال کرنے والوں کی اکثریت یونیورسٹی کے طالب علموں کی ہے۔ اس گروپ کی ضروریات کے لیے اسے بہتر بنانے کے لیے، آپ نے خاص طور پر اس کے لیے کسی دوسرے ڈویلپر سے ایکزیز جنریشن سسٹم کا آرڈر دیا۔ ترقیاتی ٹیم نے تحقیق کی، درجہ بندی مرتب کی، مصنوعی ذہانت سے منسلک کیا، ٹریفک جام، موسم، وغیرہ کے ساتھ انضمام شامل کیا۔ اب آپ کے پاس طلباء کے لیے بہانے پیدا کرنے کے لیے ایک لائبریری ہے، لیکن اس کے ساتھ بات چیت کرنے کا انٹرفیس مختلف ہے - StudentExcuse:
public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
انٹرفیس کے دو طریقے ہیں: generateExcuseجو ایک عذر پیدا کرتا ہے، اور dislikeExcuseجو عذر کو روکتا ہے تاکہ یہ مستقبل میں ظاہر نہ ہو۔ فریق ثالث کی لائبریری ترمیم کے لیے بند ہے - آپ اس کا سورس کوڈ تبدیل نہیں کر سکتے۔ نتیجے کے طور پر، آپ کے سسٹم میں دو کلاسیں ہیں جو انٹرفیس کو نافذ کرتی ہیں Excuse، اور ایک لائبریری SuperStudentExcuseجس میں انٹرفیس کو لاگو کیا جاتا ہے StudentExcuse:
public class SuperStudentExcuse implements StudentExcuse {
   @Override
   public String generateExcuse() {
       // Логика нового функционала
       return "Невероятная отговорка, адаптированная под текущее состояние погоды, пробки or сбои в расписании общественного транспорта.";
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Добавляет причину в черный список
   }
}
کوڈ کو تبدیل نہیں کیا جا سکتا۔ موجودہ اسکیم اس طرح نظر آئے گی: اڈاپٹر - 2 ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟سسٹم کا یہ ورژن صرف Excuse انٹرفیس کے ساتھ کام کرتا ہے۔ آپ کوڈ کو دوبارہ نہیں لکھ سکتے: ایک بڑی ایپلیکیشن میں، اس طرح کی تبدیلیوں میں کافی وقت لگ سکتا ہے یا ایپلی کیشن کی منطق کو توڑ سکتا ہے۔ آپ مرکزی انٹرفیس کو متعارف کرانے اور درجہ بندی کو بڑھانے کا مشورہ دے سکتے ہیں: اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے - 3ایسا کرنے کے لیے، آپ کو انٹرفیس کا نام تبدیل کرنے کی ضرورت ہے Excuse۔ لیکن سنگین ایپلی کیشنز میں اضافی درجہ بندی ناپسندیدہ ہے: ایک عام جڑ عنصر متعارف کرانے سے فن تعمیر ٹوٹ جاتا ہے۔ آپ کو ایک انٹرمیڈیٹ کلاس نافذ کرنا چاہئے جو آپ کو کم سے کم نقصان کے ساتھ نئی اور پرانی فعالیت کو استعمال کرنے کی اجازت دے گی۔ مختصر میں، آپ کو ایک اڈاپٹر کی ضرورت ہے .

اڈاپٹر پیٹرن کیسے کام کرتا ہے۔

ایک اڈاپٹر ایک انٹرمیڈیٹ آبجیکٹ ہے جو ایک شے کے طریقوں کو کال کرتا ہے جو دوسرے کے لیے قابل فہم ہوتا ہے۔ آئیے اپنی مثال کے لیے ایک اڈاپٹر نافذ کریں اور اسے کال کریں Middleware۔ ہمارے اڈاپٹر کو ایک ایسا انٹرفیس نافذ کرنا چاہیے جو کسی ایک چیز کے ساتھ مطابقت رکھتا ہو۔ رہنے دو Excuse. اس کا شکریہ، Middlewareیہ پہلی چیز کے طریقوں کو کال کر سکتا ہے. Middlewareکالز وصول کرتا ہے اور انہیں مطابقت پذیر شکل میں دوسرے آبجیکٹ تک پہنچاتا ہے۔ Middlewareطریقوں کے ساتھ کسی طریقہ کا نفاذ اس طرح ہوتا ہے generateExcuseاور ایسا لگتا ہے dislikeExcuse:
public class Middleware implements Excuse { // 1. Middleware становится совместимым с an objectом WorkExcuse через интерфейс Excuse

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) { // 2. Получаем ссылку на адаптируемый an object
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse(); // 3. Адаптер реализовывает метод интерфейса
   }

    @Override
    public void dislikeExcuse(String excuse) {
        // Метод предварительно помещает отговорку в черный список БД,
        // Затем передает ее в метод dislikeExcuse an object superStudentExcuse.
    }
   // Метод likeExcuse появятся позже
}
ٹیسٹنگ (کلائنٹ کوڈ میں):
public class Test {
   public static void main(String[] args) {
       Excuse excuse = new WorkExcuse(); // Создаются an objectы классов,
       StudentExcuse newExcuse = new SuperStudentExcuse(); // Которые должны быть совмещены.
       System.out.println("Обычная причина для работника:");
       System.out.println(excuse.generateExcuse());
       System.out.println("\n");
       Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Оборачиваем новый функционал в an object-адаптер
       System.out.println("Использование нового функционала с помощью адаптера:");
       System.out.println(adaptedStudentExcuse.generateExcuse()); // Адаптер вызывает адаптированный метод
   }
}
نتیجہ:
Обычная причина для работника:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице.
Нет оправдания моему поступку. Я недостоин этой должности. Использование нового функционала с помощью адаптера
ایک ناقابل یقین بہانہ، موجودہ موسمی حالات، ٹریفک جام یا پبلک ٹرانسپورٹ کے شیڈول میں رکاوٹوں کے مطابق ڈھال لیا گیا۔ یہ طریقہ generateExcuseبغیر کسی اضافی تبدیلی کے کال کو کسی اور شے میں منتقل کرتا ہے۔ طریقہ کار dislikeExcuseکے لیے پہلے بہانے کو ڈیٹا بیس کی بلیک لسٹ میں رکھنا ضروری تھا۔ اضافی انٹرمیڈیٹ ڈیٹا پروسیسنگ کی وجہ سے اڈاپٹر پیٹرن کو پسند کیا جاتا ہے۔ لیکن اس طریقہ کا کیا ہوگا likeExcuseجو انٹرفیس میں ہے Excuse، لیکن اس میں نہیں StudentExcuse؟ یہ آپریشن نئی فعالیت میں تعاون یافتہ نہیں ہے۔ ایسی صورت میں، وہ ایک استثناء کے ساتھ آئے UnsupportedOperationException: اگر درخواست کردہ آپریشن کی حمایت نہیں کی جاتی ہے تو اسے پھینک دیا جاتا ہے۔ آئیے اس کو استعمال کریں۔ نئی کلاس کا نفاذ ایسا لگتا ہے Middleware:
public class Middleware implements Excuse {

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) {
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse();
   }

   @Override
   public void likeExcuse(String excuse) {
       throw new UnsupportedOperationException("Метод likeExcuse не поддерживается в новом функционале");
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Метод обращается за дополнительной информацией к БД,
       // Затем передает ее в метод dislikeExcuse an object superStudentExcuse.
   }
}
پہلی نظر میں، یہ حل کامیاب نہیں لگتا ہے، لیکن فعالیت کو نقل کرنے سے زیادہ پیچیدہ صورت حال پیدا ہوسکتی ہے. اگر کلائنٹ توجہ رکھتا ہے اور اڈاپٹر اچھی طرح سے دستاویزی ہے، تو یہ حل قابل قبول ہے۔

اڈاپٹر کب استعمال کریں۔

  1. اگر آپ کو تھرڈ پارٹی کلاس استعمال کرنے کی ضرورت ہے، لیکن اس کا انٹرفیس مرکزی ایپلیکیشن کے ساتھ مطابقت نہیں رکھتا ہے۔ مندرجہ بالا مثال سے پتہ چلتا ہے کہ کس طرح ایک شیم آبجیکٹ تخلیق کیا جاتا ہے جو کالز کو ایسے فارمیٹ میں لپیٹتا ہے جو ہدف آبجیکٹ کے لیے قابل فہم ہے۔

  2. جب کئی موجودہ ذیلی طبقات میں مشترکہ فعالیت ہونی چاہیے۔ اضافی ذیلی طبقات کے بجائے (ان کی تخلیق کوڈ کی نقل کا باعث بنے گی)، بہتر ہے کہ اڈاپٹر استعمال کریں۔

فائدے اور نقصانات

فائدہ: اڈاپٹر کلائنٹ سے ایک آبجیکٹ سے دوسری چیز پر کارروائی کی درخواستوں کی تفصیلات چھپاتا ہے۔ کلائنٹ کوڈ ڈیٹا کو فارمیٹ کرنے یا ٹارگٹ میتھڈ پر کالوں کو ہینڈل کرنے کے بارے میں نہیں سوچتا ہے۔ یہ بہت پیچیدہ ہے، اور پروگرامرز سست ہیں :) نقصان: پراجیکٹ کا کوڈ بیس اضافی کلاسوں کی وجہ سے پیچیدہ ہے، اور اگر بڑی تعداد میں متضاد پوائنٹس ہیں، تو ان کی تعداد بے قابو ہو سکتی ہے۔

اگواڑے اور ڈیکوریٹر کے ساتھ الجھن میں نہ پڑیں۔

سطحی جانچ پر، اڈاپٹر کو اگواڑے اور ڈیکوریٹر کے نمونوں کے ساتھ الجھن میں ڈالا جا سکتا ہے۔ اڈاپٹر اور اگواڑے کے درمیان فرق یہ ہے کہ ایک اگواڑا ایک نیا انٹرفیس متعارف کراتا ہے اور پورے سب سسٹم کو لپیٹتا ہے۔ ٹھیک ہے، ڈیکوریٹر، اڈاپٹر کے برعکس، آبجیکٹ کو خود تبدیل کرتا ہے، نہ کہ انٹرفیس۔

مرحلہ وار نفاذ کا الگورتھم

  1. سب سے پہلے، اس بات کو یقینی بنائیں کہ کوئی مسئلہ ہے جو یہ پیٹرن حل کر سکتا ہے.

  2. ایک کلائنٹ انٹرفیس کی وضاحت کریں جس کی جانب سے ایک اور کلاس استعمال کی جائے گی۔

  3. پچھلے مرحلے میں بیان کردہ انٹرفیس کی بنیاد پر ایک اڈاپٹر کلاس لاگو کریں۔

  4. اڈاپٹر کلاس میں، ایک فیلڈ بنائیں جو آبجیکٹ کا حوالہ محفوظ کرے۔ یہ حوالہ کنسٹرکٹر میں گزرا ہے۔

  5. اڈاپٹر میں کلائنٹ کے تمام انٹرفیس طریقوں کو لاگو کریں۔ طریقہ یہ کر سکتا ہے:

    • ترمیم کے بغیر کال کی منتقلی؛

    • ڈیٹا کو تبدیل کریں، ٹارگٹ میتھڈ پر کالز کی تعداد میں اضافہ/کم کریں، ڈیٹا کی کمپوزیشن کو مزید وسعت دیں، وغیرہ۔

    • آخری حربے کے طور پر، اگر کوئی خاص طریقہ مطابقت نہیں رکھتا ہے، تو ایک UnsupportedOperationException پھینک دیں، جس کو سختی سے دستاویز کرنے کی ضرورت ہے۔

  6. اگر ایپلیکیشن صرف کلائنٹ انٹرفیس کے ذریعے اڈاپٹر استعمال کرتی ہے (جیسا کہ اوپر کی مثال میں)، اس سے مستقبل میں اڈاپٹر کو بغیر کسی تکلیف کے بڑھایا جا سکے گا۔

بلاشبہ، ایک ڈیزائن پیٹرن تمام بیماریوں کا علاج نہیں ہے، لیکن اس کی مدد سے آپ مختلف انٹرفیس کے ساتھ اشیاء کی عدم مطابقت کے مسئلے کو خوبصورتی سے حل کر سکتے ہیں۔ ایک ڈویلپر جو بنیادی نمونوں کو جانتا ہے ان سے کئی قدم اوپر ہے جو صرف الگورتھم لکھنا جانتے ہیں، کیونکہ سنجیدہ ایپلی کیشنز بنانے کے لیے ان کی ضرورت ہوتی ہے۔ کوڈ کو دوبارہ استعمال کرنا کم مشکل ہو جاتا ہے اور برقرار رکھنا ایک خوشی کی بات ہے۔ آج کیلئے بس اتنا ہی! لیکن ہم جلد ہی مختلف ڈیزائن کے نمونوں سے اپنی واقفیت جاری رکھیں گے :)
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION