SOLIDE dans la pratique. Principe ouvert-fermé et ActiveQuery Yii2

Une fois dans une conversation de travail, l'un de mes collègues programmeurs a remarqué que toutes sortes de principes et de modèles de conception de logiciels sont bons à utiliser lors de tâches de test, mais dans de vrais projets de combat, ils ne sont généralement pas applicables. Pourquoi donc? Il y a deux principales raisons: 





  • Les principes et modèles prennent trop de temps à mettre en œuvre. 





  • Le code devient lourd et difficile à comprendre. 





Dans une série d'articles «En pratique», j'essaierai de dissiper ces idées préconçues en démontrant des cas qui implémentent des principes de conception dans des tâches pratiques de telle sorte que ce code ne soit pas trop compliqué et qu'il prenne un temps raisonnable pour l'écrire. Voici le premier article de cette série. 





Le point de départ

Nous travaillons sur un projet en Yii2 , dans lequel nous utilisons  ActiveRecord



. Le code client charge un ensemble de données à l'aide de  ActiveRecord::find()







class ClientClass  


    //  ... 

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

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

    //  ... 

      
      



Ce code applique un ActiveQueryInterface



ensemble fixe de conditions à l' instance d'implémentation   et renvoie l'instance configurée pour une utilisation future. 





Que faire si vous devez ajouter de nouvelles conditions à la demande?

, , . 





$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(); 
    } 
      
      



 

  • Nous avons résolu notre problème en  complétant la  méthode d'origine avec un seul appel (intervention minimale dans le code d'origine). 





  • Le comportement par défaut de la méthode d'origine n'a pas changé. 





  • La nouvelle méthode appelée à partir de la méthode d'origine n'implémente  applyFilters()



    pas sa propre logique - toute la logique est déléguée aux classes de filtre. Ainsi, nous avons laissé inchangé le comportement de toute la classe d'origine. 












All Articles