صلبة في الممارسة. مبدأ مفتوح مغلق و ActiveQuery Yii2

بمجرد الدخول في محادثة عمل ، لاحظ أحد زملائي المبرمجين أن جميع أنواع مبادئ وأنماط تصميم البرامج جيدة للاستخدام عند القيام بمهام الاختبار ، ولكن في المشاريع القتالية الحقيقية ، لا يمكن تطبيقها عادةً. لماذا هذا؟ هناك سببان رئيسيان: 





  • تستغرق المبادئ والأنماط وقتًا طويلاً في التنفيذ. 





  • يصبح الرمز مرهقًا ويصعب فهمه. 





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





نقطة البداية

نحن نعمل على مشروع في Yii2 نستخدم فيه  ActiveRecord



. يقوم رمز العميل بتحميل مجموعة من البيانات باستخدام ملف  ActiveRecord::find()







class ClientClass  


    //  ... 

    public function buildQuery(): ActiveQueryImplementation 
    
        $query = ActiveRecordModel::find(); //   ActiveQuery   
        $query->active()->unfinished(); //  ,     ActiveQuery         

        return $query; //    ActiveQuery      ,  $query->all(); 
    } 

    //  ... 

      
      



يطبق هذا الرمز مجموعة ActiveQueryInterface



ثابتة من الشروط على المثيل الذي ينفذ   ويعيد المثيل الذي تم تكوينه للاستخدام لاحقًا. 





ماذا لو احتجت إلى إضافة شروط جديدة إلى الطلب؟

, , . 





$query->active()->unfinished()->newConditionA()->newConditionB(); 
      
      



! , , . 





, ? ? 





. , , , , . ? ... 





-

 , - SOLID : 





. 





   ,   .  





-,    , , .









class ClientClass  
{ 
    /** 
     * @var ActiveQueryFilter[] 
     */ 
    public $filters = []; //        

    //  ... 

    public function buildQuery(): ActiveQueryImplementation
    
        $query = ActiveRecordModel::find(); 
        $query->active()->unfinished();   
        $this->applyFilters($query); //     

				return $query; 
    } 

    private function applyFilters(ActiveQueryImplementation &$query): void  
    { 
        foreach ($this->filters as $filter) { 
            $filter->applyTo($query); 
        } 
    } 

    //  ... 

      
      



 ActiveQueryFitler



  applyTo()



, . 





interface ActiveQueryFilter 
{ 
    public function applyTo(ActiveQuery $query): void
      
      



 ActiveQueryFilter







class NewConditionsAAndBFilter implements ActiveQueryFilter 
{ 
    public function applyTo(ActiveQuery $query): void  
    
        $query->newCondtionA()->newConditionB(); 
    } 
      
      



 

  • لقد حللنا مشكلتنا عن طريق  إكمال  الطريقة الأصلية بمكالمة واحدة فقط (الحد الأدنى من التدخل في الكود الأصلي). 





  • لم يتغير السلوك الافتراضي للطريقة الأصلية. 





  • الطريقة الجديدة التي يتم استدعاؤها من الطريقة الأصلية  applyFilters()



    لا تنفذ منطقها الخاص - يتم تفويض كل منطق إلى فئات التصفية. وهكذا ، تركنا سلوك الفصل الأصلي بأكمله دون تغيير. 












All Articles