CodeGym /جاوا بلاگ /Random-UR /اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟
John Squirrels
سطح
San Francisco

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

گروپ میں شائع ہوا۔
سافٹ ویئر ڈویلپمنٹ کو غیر مطابقت پذیر اجزاء کے ذریعہ مزید مشکل بنا دیا گیا ہے جن کو مل کر کام کرنے کی ضرورت ہے۔ مثال کے طور پر، اگر آپ کو جاوا کے پہلے ورژن میں لکھے گئے پرانے پلیٹ فارم کے ساتھ ایک نئی لائبریری کو ضم کرنے کی ضرورت ہے، تو آپ کو غیر مطابقت پذیر اشیاء، یا اس کے بجائے غیر مطابقت پذیر انٹرفیس کا سامنا کرنا پڑ سکتا ہے۔ اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟  - 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[] excuses = {"in an incredible confluence of circumstances, I ran out of hot water and had to wait until sunlight, focused using a magnifying glass, heated a mug of water so that I could wash.",
   "the artificial intelligence in my alarm clock failed me, waking me up an hour earlier than normal. Because it is winter, I thought it was still nighttime and I fell back asleep. Everything after that is a bit hazy.",
   "my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia."};
   private String [] apologies = {"This will not happen again, of course. I'm very sorry.", "I apologize for my unprofessional behavior.", "There is no excuse for my actions. I am not worthy of this position."};

   @Override
   public String generateExcuse() { // Randomly select an excuse from the array
       String result = "I was late today because " + excuses[(int) Math.round(Math.random() + 1)] + "\\n" +
               apologies[(int) Math.round(Math.random() + 1)];
       return result;
   }

   @Override
   public void likeExcuse(String excuse) {
       // Duplicate the element in the array so that its chances of being chosen are higher
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Remove the item from the array
   }
}
آئیے اپنی مثال کی جانچ کریں:

Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
آؤٹ پٹ:
"I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
I apologize for my unprofessional behavior.
اب تصور کریں کہ آپ نے ایک عذر پیدا کرنے والی سروس شروع کی ہے، اعداد و شمار جمع کیے ہیں، اور محسوس کیا ہے کہ آپ کے زیادہ تر صارفین یونیورسٹی کے طالب علم ہیں۔ اس گروپ کو بہتر طریقے سے خدمت کرنے کے لیے، آپ نے ایک دوسرے ڈویلپر سے ایک ایسا نظام بنانے کو کہا جو خاص طور پر یونیورسٹی کے طلباء کے لیے بہانے پیدا کرے۔ ترقیاتی ٹیم نے مارکیٹ ریسرچ کی، بہانے درجہ بندی کی، کچھ مصنوعی ذہانت کو جوڑ دیا، اور سروس کو ٹریفک رپورٹس، موسم کی رپورٹس وغیرہ کے ساتھ مربوط کیا۔ اب آپ کے پاس یونیورسٹی کے طلباء کے لیے بہانے پیدا کرنے کے لیے ایک لائبریری ہے، لیکن اس کا انٹرفیس مختلف ہے: StudentExcuse.

public interface StudentExcuse {
   String generateExcuse();
   void dislikeExcuse(String excuse);
}
اس انٹرفیس کے دو طریقے ہیں:، generateExcuseجو ایک عذر پیدا کرتا ہے، اور dislikeExcuse، جو عذر کو مستقبل میں دوبارہ ظاہر ہونے سے روکتا ہے۔ تھرڈ پارٹی لائبریری میں ترمیم نہیں کی جا سکتی، یعنی آپ اس کا سورس کوڈ تبدیل نہیں کر سکتے۔ اب ہمارے پاس ایک ایسا نظام ہے جس میں دو کلاسز ہیں جو Excuseانٹرفیس کو نافذ کرتی ہیں، اور ایک لائبریری جس میں ایک SuperStudentExcuseکلاس ہے جو StudentExcuseانٹرفیس کو نافذ کرتی ہے:

public class SuperStudentExcuse implements StudentExcuse {
   @Override
   public String generateExcuse() {
       // Logic for the new functionality
       return "An incredible excuse adapted to the current weather conditions, traffic jams, or delays in public transport schedules.";
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // Adds the reason to a blacklist
   }
}
کوڈ کو تبدیل نہیں کیا جا سکتا۔ موجودہ طبقاتی درجہ بندی اس طرح نظر آتی ہے: اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟  - 2سسٹم کا یہ ورژن صرف Excuse انٹرفیس کے ساتھ کام کرتا ہے۔ آپ کوڈ کو دوبارہ نہیں لکھ سکتے: ایک بڑی ایپلیکیشن میں، ایسی تبدیلیاں کرنا ایک طویل عمل بن سکتا ہے یا ایپلیکیشن کی منطق کو توڑ سکتا ہے۔ ہم ایک بنیادی انٹرفیس متعارف کروا سکتے ہیں اور درجہ بندی کو بڑھا سکتے ہیں: اڈاپٹر ڈیزائن پیٹرن کن مسائل کو حل کرتا ہے؟  - 3ایسا کرنے کے لیے، ہمیں Excuseانٹرفیس کا نام تبدیل کرنا ہوگا۔ لیکن سنجیدہ ایپلی کیشنز میں اضافی درجہ بندی ناپسندیدہ ہے: ایک عام جڑ عنصر متعارف کرانے سے فن تعمیر ٹوٹ جاتا ہے۔ آپ کو ایک انٹرمیڈیٹ کلاس لاگو کرنا چاہئے جو ہمیں کم سے کم نقصانات کے ساتھ نئی اور پرانی دونوں فعالیتوں کو استعمال کرنے دے گی۔ مختصر میں، آپ کو ایک اڈاپٹر کی ضرورت ہے .

اڈاپٹر پیٹرن کے پیچھے اصول

ایک اڈاپٹر ایک انٹرمیڈیٹ آبجیکٹ ہے جو ایک آبجیکٹ کی میتھڈ کالز کو دوسرے کو سمجھنے کی اجازت دیتا ہے۔ آئیے اپنی مثال کے لیے ایک اڈاپٹر نافذ کریں اور اسے کال کریں Middleware۔ ہمارے اڈاپٹر کو ایک ایسا انٹرفیس نافذ کرنا چاہیے جو کسی ایک چیز کے ساتھ مطابقت رکھتا ہو۔ رہنے دو Excuse. یہ Middlewareپہلی چیز کے طریقوں کو کال کرنے کی اجازت دیتا ہے۔ Middlewareکالز وصول کرتا ہے اور انہیں مطابقت پذیر طریقے سے دوسرے آبجیکٹ پر بھیجتا ہے۔ یہاں اور طریقوں Middlewareکے ساتھ عمل درآمد ہے : generateExcusedislikeExcuse

public class Middleware implements Excuse { // 1. Middleware becomes compatible with WorkExcuse objects via the Excuse interface

   private StudentExcuse superStudentExcuse;

   public Middleware(StudentExcuse excuse) { // 2. Get a reference to the object being adapted
       this.superStudentExcuse = excuse;
   }

   @Override
   public String generateExcuse() {
       return superStudentExcuse.generateExcuse(); // 3. The adapter implements an interface method
   }

    @Override
    public void dislikeExcuse(String excuse) {
        // The method first adds the excuse to the blacklist,
        // Then passes it to the dislikeExcuse method of the superStudentExcuse object.
    }
   // The likeExcuse method will appear later
}
ٹیسٹنگ (کلائنٹ کوڈ میں):

public class Test {
   public static void main(String[] args) {
       Excuse excuse = new WorkExcuse(); // We create objects of the classes
       StudentExcuse newExcuse = new SuperStudentExcuse(); // that must be compatible.
       System.out.println("An ordinary excuse for an employee:");
       System.out.println(excuse.generateExcuse());
       System.out.println("\n");
       Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Wrap the new functionality in the adapter object
       System.out.println("Using new functionality with the adapter:");
       System.out.println(adaptedStudentExcuse.generateExcuse()); // The adapter calls the adapted method
   }
}
آؤٹ پٹ:
An ordinary excuse for an employee:
I was late today because my pre-holiday mood slows metabolic processes in my body, leading to depression and insomnia.
There is no excuse for my actions. I am not worthy of this position. Using new functionality with the adapter:
موجودہ موسمی حالات، ٹریفک جام، یا پبلک ٹرانسپورٹ کے نظام الاوقات میں تاخیر کے مطابق ایک ناقابل یقین عذر۔ یہ 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("The likeExcuse method is not supported by the new functionality");
   }

   @Override
   public void dislikeExcuse(String excuse) {
       // The method accesses a database to fetch additional information,
       // and then passes it to the superStudentExcuse object's dislikeExcuse method.
   }
}
پہلی نظر میں، یہ حل بہت اچھا نہیں لگتا، لیکن فعالیت کی نقل کرنا صورتحال کو پیچیدہ بنا سکتا ہے۔ اگر کلائنٹ توجہ دیتا ہے، اور اڈاپٹر اچھی طرح سے دستاویزی ہے، تو اس طرح کا حل قابل قبول ہے.

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

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

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

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

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

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

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

مرحلہ وار الگورتھم

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

  2. کلائنٹ انٹرفیس کی وضاحت کریں جو غیر مطابقت پذیر اشیاء کے ساتھ بالواسطہ تعامل کے لیے استعمال کیا جائے گا۔

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

  4. اڈاپٹر کلاس میں، اڈاپٹی آبجیکٹ کا حوالہ ذخیرہ کرنے کے لیے ایک فیلڈ بنائیں۔ یہ حوالہ کنسٹرکٹر کو دیا جاتا ہے۔

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

    • بغیر کسی تبدیلی کے کالز پاس کریں۔

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

    • انتہائی صورتوں میں، اگر کوئی خاص طریقہ مطابقت نہیں رکھتا ہے، تو ایک UnsupportedOperationException پھینک دیں۔ غیر تعاون یافتہ آپریشنز کو سختی سے دستاویزی ہونا چاہیے۔

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

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