SÓLIDO en la práctica. Principio abierto-cerrado y ActiveQuery Yii2

Una vez en una conversación de trabajo, uno de mis compañeros programadores notó que todo tipo de principios y patrones de diseño de software son buenos para usar cuando se realizan tareas de prueba, pero en proyectos de combate reales, generalmente no son aplicables. ¿Porqué es eso? Hay dos razones principales: 





  • Los principios y patrones tardan demasiado en implementarse. 





  • El código se vuelve engorroso y difícil de entender. 





En una serie de artículos "En la práctica" intentaré disipar estas ideas preconcebidas demostrando casos que implementan principios de diseño en tareas prácticas de tal manera que este código no sea demasiado complicado y lleve un tiempo razonable escribirlo. Aquí está el primer artículo de esta serie. 





El punto de partida

Estamos trabajando en un proyecto en Yii2 , en el que usamos  ActiveRecord



. El código de cliente carga un conjunto de datos usando  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 un ActiveQueryInterface



conjunto fijo de condiciones a la instancia de implementación   y devuelve la instancia configurada para su uso posterior. 





¿Qué sucede si necesita agregar nuevas condiciones a la solicitud?

, , . 





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



 

  • Hemos resuelto nuestro problema  completando el  método original con una sola llamada (intervención mínima en el código original). 





  • El comportamiento predeterminado del método original no ha cambiado. 





  • El nuevo método llamado desde el método original  applyFilters()



    no implementa su propia lógica; toda la lógica se delega a las clases de filtro. Por tanto, hemos dejado sin cambios el comportamiento de toda la clase original. 












All Articles