SÓLIDO na prática. Princípio aberto-fechado e ActiveQuery Yii2

Uma vez em uma conversa de trabalho, um de meus colegas programadores notou que todos os tipos de princípios e padrões de design de software são bons para usar ao fazer tarefas de teste, mas em projetos reais de combate eles geralmente não são aplicáveis. Por que é que? Há duas razões principais: 





  • Princípios e padrões demoram muito para serem implementados. 





  • O código torna-se pesado e difícil de entender. 





Em uma série de artigos "Na prática", tentarei dissipar esses preconceitos demonstrando casos que implementam princípios de design em tarefas práticas de forma que esse código não seja muito complicado e leve um tempo razoável para escrevê-lo. Aqui está o primeiro artigo desta série. 





O ponto de partida

Estamos trabalhando em um projeto no Yii2 , no qual usamos  ActiveRecord



. O código do cliente carrega um conjunto de dados usando o  ActiveRecord::find()







class ClientClass  


    //  ... 

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

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

    //  ... 

      
      



Este código aplica um ActiveQueryInterface



conjunto fixo de condições à instância de implementação   e retorna a instância configurada para uso futuro. 





E se você precisar adicionar novas condições à solicitação?

, , . 





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



 

  • Resolvemos nosso problema  completando o  método original com apenas uma chamada (intervenção mínima no código original). 





  • O comportamento padrão do método original não mudou. 





  • Um novo método chamado a partir do método original  applyFilters()



    não implementa sua própria lógica - toda a lógica é delegada às classes de filtro. Assim, deixamos o comportamento de toda a classe original inalterado. 












All Articles