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

نمط الأمر

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

إن Command Pattern هو نمط تصميم سلوكي يحوّل طلبًا إلى كائن مستقل يحتوي على جميع المعلومات المتعلقة بالطلب. يتيح لك هذا التحويل تمرير الطلبات كوسائط methods، وتأخير تنفيذ الطلب أو وضعه في قائمة انتظار، ودعم العمليات القابلة للتراجع.

تخيّل مطعمًا.

عندما تطلب الطعام، يكتب النادل طلبك على إيصال (command)، ثم يأخذه إلى المطبخ، ويقوم الطاهي بتنفيذه. لا يحتاج النادل إلى معرفة كيفية الطهي؛ فهو يكتفي بتسليم command.

يفصل هذا بين مُقدِّم الطلب والمنفِّذ.

إليك تنفيذًا أساسيًا:

<?php
interface Command {
    public function execute(): string;
}
class Light {
    public function on(): string { return "Light is ON"; }
    public function off(): string { return "Light is OFF"; }
}
class LightOnCommand implements Command {
    public function __construct(private Light $light) {}
    
    public function execute(): string {
        return $this->light->on();
    }
}
class LightOffCommand implements Command {
    public function __construct(private Light $light) {}
    
    public function execute(): string {
        return $this->light->off();
    }
}

يُشغّل invoker الأوامر دون معرفة ما تفعله:

<?php
class RemoteControl {
    public function press(Command $command): string {
        return $command->execute();
    }
}
$light = new Light();
$remote = new RemoteControl();

echo $remote->press(new LightOnCommand($light)) . "\n";
echo $remote->press(new LightOffCommand($light));

المخرجات:

Light is ON
Light is OFF

يتفوّق نمط Command عندما تحتاج إلى وضع العمليات في قائمة انتظار، أو Implement وظيفة التراجع، أو تسجيل الإجراءات. كل command مستقل بذاته، مما يجعل من السهل إضافة commands جديدة دون تعديل الشفرة الموجودة.

challenge icon

التحدي

سهل

لنَبْنِ نظام أوامر لمحرر نصوص باستخدام نمط Command. غالبًا ما تحتاج محررات النصوص إلى دعم عمليات مثل كتابة النص وحذف النص والتراجع عن الإجراءات: تصبح كل عملية كائن أمر مستقلًا يمكن تنفيذه من خلال واجهة موحّدة.

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

  • Command.php: Define واجهة Command ذات method واحدة هي execute(): string. وهذا يحدد contract الذي يجب أن تتبعه جميع أوامر المحرر.
  • TextEditor.php، أنشئ class TextEditor تمثل المستقبل، أي الكائن الذي ينفذ العمل فعليًا. يجب أن يقوم المحرر بما يلي:
    • تخزين محتوى النص current (ابدأ بسلسلة نصية empty)
    • امتلاك method write(string $text): string تُلحِق النص بالمحتوى وتعيد "Written: [text]"
    • امتلاك method clear(): string تُفرغ المحتوى وتعيد "Content cleared"
    • امتلاك method getContent(): string التي تعيد المحتوى current
  • Commands.php: أدرج ملفي Command وTextEditor. أنشئ classين للأوامر ينفذان واجهة Command:
    • WriteCommand: تأخذ TextEditor وسلسلة نصية في constructor الخاص بها. تستدعي method execute() الخاصة بها method write() للمحرر وتعيد النتيجة.
    • ClearCommand: تأخذ TextEditor في constructor الخاص بها. تستدعي method execute() الخاصة بها method clear() للمحرر وتعيد النتيجة.
  • main.php: أدرج ملف Commands. ستتلقى مدخلين: نوع command ("write" أو "clear") وسلسلة نصية (تُستخدم فقط مع أوامر الكتابة).

    أنشئ instance من TextEditor. وبناءً على نوع command، أنشئ كائن الأمر appropriate. ثم أنشئ function invoker أو آلية بسيطة تستدعي execute() على الأمر وتطبع النتيجة.

    في سطر جديد، اطبع المحتوى current للمحرر بهذا format: Content: [content] (إذا كان فارغًا، اطبع فقط Content: دون أي شيء بعد المسافة).

يوضح هذا التحدي كيف يقوم نمط Command بتغليف كل عملية في شكل كائن. لا يحتاج invoker إلى معرفة ما إذا كان ينفذ command للكتابة أو للمسح. فهو يستدعي ببساطة execute() ويترك للأمر التعامل مع التفاصيل.

جرّب بنفسك

<?php

require_once 'Commands.php';

// اقرأ الإدخال
$commandType = trim(fgets(STDIN)); // "write" أو "clear"
$text = trim(fgets(STDIN));         // النص لأمر write

// TODO: أنشئ مثيلاً من TextEditor

// TODO: بناءً على نوع الأمر، أنشئ كائن الأمر المناسب
// - إذا كان "write"، أنشئ WriteCommand مع المحرر والنص
// - إذا كان "clear"، أنشئ ClearCommand مع المحرر

// TODO: أنشئ آلية invoker تستدعي execute() على الأمر
// وتطبع النتيجة

// TODO: اطبع المحتوى الحالي للمحرر بالتنسيق: "Content: [content]"
// (إذا كان فارغًا، اطبع فقط "Content: " بدون أي شيء بعد المسافة)

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

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

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

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