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

نمط المحول

جزء من قسم البرمجة كائنية التوجه في رحلة PHP على Coddy. الدرس 76 من 91.

إن نمط Adapter هو نمط تصميم هيكلي يتيح للكائنات ذات الواجهات غير المتوافقة العمل معًا. ويعمل كجسر بين واجهتين، إذ يترجم الاستدعاءات من تنسيق إلى آخر.

تخيّل أنك تبني تطبيقًا يعالج المدفوعات، وتحتاج إلى دمج مكتبة دفع تابعة لجهة خارجية. تعمل المكتبة بشكل مثالي، لكن واجهتها لا تتوافق مع ما يتوقعه كودك. بدلًا من إعادة كتابة تطبيقك بالكامل، تنشئ adapter يترجم بين الاثنين.

<?php
// الواجهة التي يتوقعها تطبيقك
interface PaymentProcessor {
    public function pay(float $amount): string;
}

// مكتبة طرف ثالث بواجهة مختلفة
class StripeAPI {
    public function createCharge(int $cents, string $currency): string {
        return "Charged {$cents} {$currency} via Stripe";
    }
}

ينفّذ الـ adapter واجهتك المتوقعة مع استخدام الفئة التابعة لجهة خارجية داخليًا:

<?php
class StripeAdapter implements PaymentProcessor {
    public function __construct(private StripeAPI $stripe) {}
    
    public function pay(float $amount): string {
        $cents = (int)($amount * 100);
        return $this->stripe->createCharge($cents, 'USD');
    }
}

$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);

المخرَج:

Charged 2999 USD via Stripe

يقوم adapter بتحويل الدولارات إلى سنتات ويستدعي الـ method المناسب. لا يعرف كود application لديك سوى PaymentProcessor، ويظل غير مدرك بسعادة للمتطلبات الخاصة بـ Stripe. إذا انتقلت لاحقًا إلى مزود دفع different، فما عليك سوى إنشاء adapter جديد دون تغيير كودك الحالي.

challenge icon

التحدي

سهل

لنبنِ نظامًا لتحويل درجات الحرارة باستخدام نمط Adapter. لديك مستشعر درجة حرارة قديم يُخرج القراءات بوحدة Fahrenheit، لكن تطبيق الطقس الحديث لديك expects جميع درجات الحرارة بوحدة Celsius. بدلًا من تعديل أيٍّ من النظامين، ستنشئ adapter يربط بينهما.

ستنظّم الشيفرة البرمجية عبر أربعة ملفات:

  • TemperatureSensor.php: Define واجهة TemperatureSensor التي يتوقعها تطبيق الطقس لديك. يجب أن have method getTemperature(): float تُعيد درجة الحرارة بوحدة Celsius.
  • LegacySensor.php: Create class LegacySensor تحاكي hardware القديم. هذه class لها interface different عن الذي تحتاجه application:
    • تأخذ قراءة Fahrenheit في constructor الخاص بها (استخدم constructor promotion)
    • لها method readFahrenheit(): float تُعيد قيمة Fahrenheit المخزنة
  • LegacySensorAdapter.php: ضمّن كلاً من interface ‏TemperatureSensor وclass ‏LegacySensor. Create class LegacySensorAdapter التي implements ‏TemperatureSensor وتغلف كائنًا من LegacySensor. يجب أن يقوم adapter لديك بما يلي:
    • accept كائنًا من LegacySensor في constructor الخاص به
    • Implement ‏getTemperature() من خلال قراءة قيمة Fahrenheit من المستشعر القديم وتحويلها إلى Celsius باستخدام formula: (fahrenheit - 32) * 5 / 9
  • main.php: ضمّن ملف LegacySensorAdapter. ستتلقى input واحدًا: درجة حرارة بوحدة Fahrenheit.

    Create كائنًا من LegacySensor باستخدام درجة الحرارة المُدخلة، ثم غلّفه داخل LegacySensorAdapter. Call ‏getTemperature() على adapter واطبع النتيجة مقربةً إلى منزلتين عشريتين.

    يجب أن يكون تنسيق Output: Temperature: [celsius]C

يوضح هذا التحدي كيف يتيح لك Adapter Pattern دمج واجهات غير متوافقة دون تعديل الشيفرة الموجودة. يعمل تطبيق الطقس لديك حصريًا مع interface ‏TemperatureSensor، ومن دون أي معرفة بأن القراءات الفعلية تأتي من مستشعر Fahrenheit قديم.

جرّب بنفسك

<?php
require_once 'LegacySensorAdapter.php';

// اقرأ الإدخال
$fahrenheit = floatval(trim(fgets(STDIN)));

// TODO: أنشئ LegacySensor بدرجة حرارة الإدخال
// TODO: غلّفه في LegacySensorAdapter
// TODO: استدعِ getTemperature() على المحول
// TODO: اطبع النتيجة مقربة إلى منزلتين عشريتين
// تنسيق الإخراج: Temperature: [celsius]C

?>
quiz iconاختبر نفسك

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

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم PHP عبر الإنترنت