CodeGym /مدونة جافا /Random-AR /ما هي المشاكل التي يحلها نمط تصميم المحول؟
John Squirrels
مستوى
San Francisco

ما هي المشاكل التي يحلها نمط تصميم المحول؟

نشرت في المجموعة
يصبح تطوير البرمجيات أكثر صعوبة بسبب المكونات غير المتوافقة التي تحتاج إلى العمل معًا. على سبيل المثال، إذا كنت بحاجة إلى دمج مكتبة جديدة مع نظام أساسي قديم مكتوب في إصدارات سابقة من Java، فقد تواجه كائنات غير متوافقة، أو بالأحرى واجهات غير متوافقة. ما هي المشاكل التي يحلها نمط تصميم المحول؟  - 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مع الأساليب generateExcuseوالأساليب dislikeExcuse:
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