Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

نمط المحول

جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 71 من 87.

نمط المحول (Adapter Pattern) هو نمط تصميم هيكلي يسمح للواجهات غير المتوافقة بالعمل معاً. فهو يعمل كجسر بين فئتين، حيث يقوم بتحويل واجهة فئة واحدة إلى واجهة يتوقعها العميل. فكر فيه كمحول طاقة يتيح لك توصيل جهاز أوروبي بمقبس أمريكي.

تخيل أن لديك واجهة MediaPlayer موجودة بالفعل تقوم بتشغيل ملفات الصوت، ولكنك تحتاج إلى دمج مكتبة خارجية تستخدم واجهة مختلفة تمامًا لتشغيل مقاطع الفيديو:

// الواجهة الحالية التي يستخدمها الكود الخاص بك
interface MediaPlayer {
    void play(String filename);
}

// فئة من طرف ثالث بواجهة غير متوافقة
class AdvancedVideoPlayer {
    public void playVideo(String filename) {
        System.out.println("Playing video: " + filename);
    }
}

يقوم المحول (adapter) بتغليف الفئة غير المتوافقة وينفذ الواجهة المتوقعة، مترجماً الاستدعاءات بينهما:

class VideoPlayerAdapter implements MediaPlayer {
    private AdvancedVideoPlayer videoPlayer;
    
    public VideoPlayerAdapter() {
        this.videoPlayer = new AdvancedVideoPlayer();
    }
    
    public void play(String filename) {
        videoPlayer.playVideo(filename);
    }
}

الآن يمكن لكود العميل الخاص بك استخدام مشغل الفيديو من خلال واجهة MediaPlayer المألوفة:

MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4");  // المخرجات: تشغيل الفيديو: movie.mp4

يعد نمط المحول (Adapter Pattern) ذا قيمة كبيرة عند دمج الكود القديم أو مكتبات الطرف الثالث دون تعديل الكود المصدري الخاص بها. يظل العميل غير مدرك أنه يعمل مع فئة تم تكييفها—فهو ببساطة يستخدم الواجهة التي يعرفها.

challenge icon

التحدي

سهل

لنقم ببناء نظام لتحويل درجات الحرارة باستخدام نمط المحول (Adapter Pattern)! لديك تطبيق طقس حالي يعمل مع درجات الحرارة المئوية (Celsius)، ولكنك تحتاج إلى دمج مستشعر حرارة قديم يخرج القراءات بالفهرنهايت (Fahrenheit) فقط. بدلاً من تعديل أي من النظامين، ستقوم بإنشاء محول يسد هذه الفجوة.

ستقوم بتنظيم الكود الخاص بك عبر أربعة ملفات:

  • TemperatureProvider.java: حدد الواجهة (interface) التي يتوقعها تطبيق الطقس الخاص بك. يجب أن تعلن عن طريقة getTemperatureCelsius() التي تعيد قيمة من نوع double تمثل درجة الحرارة بالدرجة المئوية.
  • FahrenheitSensor.java: يمثل هذا المستشعر القديم ذو الواجهة غير المتوافقة. قم بإنشاء فئة تحتوي على حقل خاص (private double) لدرجة الحرارة بالفهرنهايت، يتم تعيينه من خلال المنشئ (constructor). يجب أن تحتوي على طريقة readFahrenheit() تعيد قيمة الفهرنهايت المخزنة.
  • SensorAdapter.java: قم بإنشاء المحول الذي يجعل مستشعر الفهرنهايت متوافقاً مع تطبيق الطقس الخاص بك. يجب أن يقوم المحول الخاص بك بتنفيذ TemperatureProvider وتغليف FahrenheitSensor. عندما يتم استدعاء getTemperatureCelsius()، يجب أن يقرأ من المستشعر ويحول القيمة إلى مئوية باستخدام الصيغة: (fahrenheit - 32) * 5 / 9.
  • Main.java: اجمع كل شيء معاً! ستتلقى مدخلاً واحداً: قراءة درجة الحرارة بالفهرنهايت (double).

    قم بإنشاء FahrenheitSensor باستخدام القيمة المدخلة. ثم قم بإنشاء SensorAdapter يغلف هذا المستشعر. قم بتخزين المحول في متغير من نوع TemperatureProvider لإثبات أن تطبيق الطقس الخاص بك يمكنه استخدامه من خلال الواجهة المتوقعة.

    اطبع النتيجة بهذا التنسيق: Temperature: [celsius] C حيث يتم تنسيق celsius إلى منزلة عشرية واحدة.

ستتلقى مدخلاً واحداً: درجة الحرارة بالفهرنهايت (double).

على سبيل المثال، مع المدخل 98.6، سيكون مخرجك:

Temperature: 37.0 C

لاحظ كيف تعمل فئة Main الخاصة بك تماماً مع واجهة TemperatureProvider — ليس لديها أي فكرة عن أن درجة الحرارة الفعلية تأتي من مستشعر فهرنهايت يتم تكييفه خلف الكواليس. هذه هي أناقة نمط المحول (Adapter Pattern)!

جرّب بنفسك

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        double fahrenheit = scanner.nextDouble();
        
        // TODO: قم بإنشاء FahrenheitSensor بالقيمة المدخلة
        
        // TODO: قم بإنشاء SensorAdapter يغلف الـ sensor
        
        // TODO: قم بتخزين الـ adapter في متغير TemperatureProvider
        
        // TODO: احصل على درجة الحرارة بـ Celsius وقم بطباعتها
        // التنسيق: "Temperature: [celsius] C" مع منزلة عشرية واحدة
        // تلميح: استخدم String.format("%.1f", value) للتنسيق
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming