JavaRush /مدونة جافا /Random-AR /ما هي المشاكل التي يحلها نمط تصميم المحول؟

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

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