مقدمة لأنماط التصميم في PHP (والاستفادة منها في دروبال)

نشرت: 2022-07-05

قال شخص ذكي ذات مرة - كود المبرمجين الجيد ، إعادة استخدام رائعة.
غالبًا ما يجد المطورون أنفسهم في حل نفس النوع من المشكلات بشكل متكرر. إعادة استخدام الكود هو حقًا الكأس المقدسة لتطوير البرمجيات. أيضًا ، من الذي لا يحب قراءة (وكتابة) كود جيد التنظيم؟ أدخل - أنماط التصميم في PHP.

أثبتت أنماط تصميم PHP أنها مفيدة للغاية للمطورين وهي حل كبير للمشكلات. يعد اتباع أفضل الممارسات أمرًا بالغ الأهمية لكتابة تعليمات برمجية فعالة. أنماط تصميم PHP هي مفهوم البرمجة الشيئية (OOP) الذي يستخدم الآن أيضًا في مشاريع دروبال 9. مع اعتماد دروبال لمفاهيم PHP و OOP الحديثة منذ الإصدار 8 ، يمكن الاستفادة من أنماط التصميم لبرمجة أنظف وأكثر قوة. في هذه المقالة ، سنناقش بعض أنماط التصميم الشائعة الاستخدام في PHP وكيفية استخدام أنماط مثل حقن التبعية في دروبال.

هل ما زلت على دروبال 7؟ اقرأ هذه المقالة للعثور على قائمة مرجعية مفيدة ستساعدك على الاستعداد لترحيل دروبال 9.

أنماط التصميم في PHP

ما هي أنماط التصميم في PHP؟

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

لماذا تستخدم أنماط تصميم PHP

بعض أهم فوائد تنفيذ أنماط التصميم في PHP هي:

  • تساعد أنماط تصميم PHP في حل المشكلات المتكررة التي تواجهها أثناء التطوير
  • استخدام أنماط التصميم في PHP يجعل التواصل بين المصممين والمطورين أكثر كفاءة
  • يمكنك أن تثق في أن المطورين الآخرين سيفهمون شفرتك لأنها تتبع أنماط التصميم
  • يساعد اتباع أفضل الممارسات في إنشاء تطبيقات أكثر قوة
  • يساعد في جعل التطوير أسرع وأسهل

أنماط التصميم المستخدمة على نطاق واسع في PHP

يمكن استخدام أنماط التصميم في مواقف مختلفة لحل مشاكل مماثلة. يوجد أكثر من 30 نمط تصميم يمكن تصنيفها على نطاق واسع إلى ثلاثة أنواع - الأنماط الإبداعية والهيكلية والسلوكية.

الأنماط الإبداعية: أنماط التصميم المستخدمة في آليات إنشاء الكائنات ، لإنشاء كائنات يمكن فصلها عن النظام الذي طبقها.

الأنماط الهيكلية: هذا يسهل التصميم من خلال تحديد طرق بسيطة لتحقيق العلاقات بين الكيانات

الأنماط السلوكية: تُستخدم لإدارة العلاقات والمسؤوليات والخوارزميات بين الكائنات

نمط المصنع

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

 interface FamilyFactoryInterface { public function create() : Family }

بعد ذلك ، قم بتنفيذ واجهة المصنع بالفئة التالية:

 class FamilyFactory implements FamilyFactoryInterface { public function create() : Family { $family = new Family(); // initialize your family return $family; } }

نمط المحول

في نمط تصميم المحول ، تحول فئة واجهة فئة إلى فئة أخرى. في هذا المثال ، لدينا فئة TextBook بها طرق getTitle () و getAuthor (). يتوقع العميل طريقة getTitleAndAuthor (). "لتكييف" SimpleBook مع demoAdapter ، لدينا فئة محول ، BookAdapter ، والتي تأخذ مثيلاً من TextBook ، وتستخدم أسلوب TextBook getTitle () و getAuthor () في طريقة getTitleAndAuthor الخاصة بها.

 <?php class TextBook { private $title; private $author; function __construct($title_in, $author_in) { $this->title = $title_in; $this->author = $author_in; } function getTitle() { return $this->title; } function getAuthor() { return $this->author; } } class BookAdapter { private $book; function __construct(TextBook $book_in) { $this->book = $book_in; } function getTitleAndAuthors() { return $this->book->getTitle().' by '.$this->book->getAuthor(); } } // client writeln('BEGIN TESTING ADAPTER PATTERN'); writeln(''); $book = new TextBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns"); $bookAdapter = new BookAdapter($book); writeln('Author and Title: '.$bookAdapter->getTitleAndAuthor()); writeln(''); writeln('END TESTING ADAPTER PATTERN'); function writeln($line_in) { echo $line_in."<br/>"; } ?>

نمط PHP Singleton

من أجل قصر إنشاء مثيل للفئة على كائن واحد ، يتم استخدام نمط مفرد في PHP. يمكن أن يكون هذا مفيدًا عند الحاجة إلى كائن واحد فقط عبر النظام. من المنطقي السماح بالوصول إلى مثيل واحد فقط لفئة معينة أثناء تصميم تطبيقات الويب. من أجل منع الإنشاء الواضح للكائنات من فئة نمط Singleton ، يتم استخدام مُنشئ خاص.

 <?php class Singleton { public static function getInstance() { static $instance = null; if (null === $instance) { $instance = new static(); } return $instance; } protected function __construct() { } private function __clone() { } private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); $obj2 = SingletonChild::getInstance(); var_dump($obj2 === Singleton::getInstance()); var_dump($obj2 === SingletonChild::getInstance()); ?>

نمط المراقب في PHP

يستخدم نمط PHP Observer لتنبيه بقية النظام حول أحداث معينة في أماكن معينة.
على سبيل المثال ، إذا احتجنا إلى إنشاء مسرح لعرض الأفلام على النقاد. نحدد مسرح الفصل بالطريقة الحالية. قبل عرض الفيلم ، نريد إرسال رسائل إلى هواتف النقاد المحمولة. بعد ذلك ، في منتصف الفيلم ، نريد إيقاف الفيلم لمدة 5 دقائق للسماح للنقاد بفاصل زمني. أخيرًا بعد انتهاء الفيلم نطلب من النقاد ترك ردهم. لذلك ، في نمط المراقب لـ PHP ، يتم إخطار كائن المراقب فقط عند تغيير الحالة.

هكذا تبدو الكود -

 class Theater { public function current(Movie $movie) : void { $critics = $movie->getCritics(); $this->message->send($critics, '...'); $movie->play(); $movie->pause(5); $this->progress->interval($critics) $movie->end(); $this->response->request($critics); } }

نمط Decorator لـ PHP

يتم استخدام نمط Decorator عندما تريد تغيير طابع الكائن في وقت التشغيل ، وبذلك ، قلل من الميراث غير الضروري وعدد الفئات. حسنًا ، يمكن شرح ذلك بالأمثلة. لنفترض أن لدينا فصولاً صوفا وسرير ، وكلاهما يستخدم SleeperInterface.

 interface SleeprInterface { public function sleep() : void; } class Sofa implements SleeperInterface { public function sleep() : void { // sleeps on sofa } } class Bed implements SleeperInterface { public function sleep() : void { // sleeps on bed } }

كل من الأرائك والأسرة لها نفس السلوك في النوم. الآن ، نحتاج إلى أرائك وأسرة أخرى بوظائف إضافية تخبر المستخدمين بتتبع النوم عند النوم على الأرائك أو الأسرة. مع الميراث يمكننا حل هذه المشكلة تمامًا مثل هذا:

 class SmartSofa extends Sofa { public function sleep() : void { parent::sleep(); $this->sleepHours(); } } class SmartBed extends Window { public function sleep() : void { parent::sleep(); $this->sleepHours(); } }


الآن لدينا 4 فصول في المجموع. ومع ذلك ، يمكننا حل هذه المشكلة بثلاث فئات فقط باستخدام نمط Decorator. إليك الطريقة:

 class SmartSleeper implements SleeperInterface { private $sleeper; public function __construct(SleeperInterface $sleeper) { $this->sleeper = $sleeper; } public function sleep() : void { $this->sleeper->sleep(); $this->sleepHours(); } } $sofa = new Sofa(); $bed = new Bed(); $smartSofa = new SmartSleeper($sofa); $smartBed = new SmartSleeper($bed);

هنا ، قدمنا ​​نوعًا جديدًا من أدوات النوم التي تعمل كبروكسي ولكن مع وظائف إضافية فوقها.

الاستفادة من أنماط التصميم في دروبال 9

في حين أن هناك العديد من أنماط التصميم التي تم إنشاؤها بالفعل داخل دروبال قبل دروبال 9 ، هناك الآن العديد من الأنماط التي لم تكن متوفرة في السابق. تحل بعض هذه الأنماط الجديدة محل الأنماط القديمة تمامًا ، بينما يقدم البعض الآخر بعض الميزات الجديدة إلى دروبال 9.
تتضمن أنماط التصميم المستخدمة في دروبال 9 ما يلي:

  • نمط البرمجة الشيئية (OOP)
  • حقن التبعية
  • نمط المصنع
  • نمط سينجلتون

OOP ليس في الحقيقة نمطًا واحدًا ، ولكنه طريقة جذرية تمامًا لتصور وهيكلة الكود الذي يتجاوز مجرد أنماط التصميم. إنه أساس الكثير من أنماط تصميم البرامج الشائعة المستخدمة اليوم ، بما في ذلك تلك المستخدمة في دروبال 9. وقد تم تقديمه في دروبال 7 ، ولكنه لم يتم استخدامه على نطاق واسع ، ولم يكن مطلوبًا. الوضع في دروبال 9 مختلف الآن ، فهو مستخدم على نطاق واسع ومطلوب.

حقن التبعية

حقن التبعية هو نمط تصميم برمجي من شأنه أن يسمح لك بإزالة التبعيات ذات الترميز الثابت وأيضًا يجعل من الممكن تغييرها إما في وقت التشغيل أو في وقت الترجمة. تعد إضافة حقن التبعية أمرًا سهلاً ولا تتداخل مع الكود الحالي الخاص بك. قدم دروبال 8 مفهوم الخدمات من أجل فصل الوظائف القابلة لإعادة الاستخدام. core.services.yml هو مثال على حقن التبعية في دروبال 9. لقد ناقشنا بالفعل نمط المصنع ونمط Singleton في PHP سابقًا.

حاليًا ، في دروبال ، يعد حقن التبعية الطريقة المفضلة للوصول إلى الخدمات واستخدامها ، ويجب استخدامه كلما أمكن ذلك. بدلاً من الاستدعاء إلى حاوية الخدمات العالمية ، يتم تمرير الخدمات بدلاً من ذلك كوسيطات إلى المُنشئ أو يتم حقنها عبر طرق setter. يُطلق على التمرير الصريح للخدمات التي يعتمد عليها كائن ما حقن التبعية . في العديد من الحالات ، يتم تمرير التبعيات صراحةً في مُنشئ الصنف.

تحقق من هذه الصفحة للعثور على جميع الخدمات المتاحة في دروبال كور. يمكنك قراءة المزيد عن الخدمات في وثائق دروبال.

لنفكر في خدمة "الكيان_type.manager" كمثال للحصول على عنوان العقدة بالمعرف = 1. من أجل حقنه في خدمتنا المخصصة ، علينا فقط أخذ اسم الخدمة وتمريره كوسيطة في ملف my_module_name.services.yml كما هو موضح أدناه:

my_module_name.services.yml

 services: my_module_name.helper: class: Drupal\my_module_name\MyModuleHelper arguments: ['@entity_type.manager']

ثم في فئة الخدمة لدينا ، علينا فقط الحصول على الخدمة في التابع __construct وتخزينها في متغير مثل هذا:

MyModuleHelper.php

 <?php namespace Drupal\my_module_name; use Drupal\Core\Entity\EntityTypeManagerInterface; /** * MyModuleHelper is a simple example of a Drupal 9 service. */ class MyModuleHelper { /** * The entity type manager. * * @var \Drupal\Core\Entity\EntityTypeManagerInterface */ protected $entityTypeManager; /** * Part of the DependencyInjection magic happening here. * * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager * The entity type manager. */ public function __construct(EntityTypeManagerInterface $entity_type_manager) { $this->entityTypeManager = $entity_type_manager; } /** * Returns a title for node_id = 1. */ public function getFirstNodeTitle() { $node = $this->entityTypeManager->getStorage('node')->load(1); return $node->getTitle(); } }

ومن ثم يمكننا استخدام خدمة مدير نوع enitity والحصول على عنوان العقدة مع nid = 1 في طريقة getFirstNodeTitle.

شكراً جزيلاً لـ Ankitha Shetty على رؤاها التي ساعدتنا في تحديث المقالة.