Foros del Web » Programando para Internet » PHP »

PHP OO Duda diseño : entre re-uso / eficiencia / evitar divergencias

Estas en el tema de Duda diseño : entre re-uso / eficiencia / evitar divergencias en el foro de PHP en Foros del Web. Gente Tengo una duda de diseño que me tiene mal..... dentro de una clase XXX que tenia un metodo de busqueda llamado find() pero ahora ...
  #1 (permalink)  
Antiguo 07/08/2013, 19:22
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Duda diseño : entre re-uso / eficiencia / evitar divergencias

Gente

Tengo una duda de diseño que me tiene mal..... dentro de una clase XXX que tenia un metodo de busqueda llamado find() pero ahora se me desdoblo su funcionalidad dos veces:

findSubNoA()
findSubWithA()
findSubNoAWithB()
findSubWithAWithB()

Nota: el codigo podria quedar unificado en una sola funcion pero requeriria algunos IF aqui y alla pues segun deba considerar A o no-A y B o no-B.

Para A/no-A la variacion SI es importante y fue lo que motivo la primera division en findSubWithA() y findSubNoA() pero en el caso de B/no-B se podria "emparchar" con unos cuantos IF.


Motivacion de la consulta: si bien en principio no necesito velocidad no se si a futuro pueda dar un uso distinto (es una clase muy general) y deba escribir de cero para arreglar el codigo si coloco muchos condincionales.


Entonces... podria hacer la implementacion de las siguientes formas:

1) Los cuatro metodos por separado y el cliente elige cual usar.
-> PROS: velocidad, menos parametros o seteos
-> CONS: duplicacion de codigo

2) Separo los metodos de busqueda como clase aparte "XXXFind" :

2a) Herencia
-> No gano demasiado re-uso y los codigos podria divergir por error.
2b) Interfaces ....
-> ni intento re-usar pero sigo con el problema de la posible divergencia.
2c) Muchos IF dentro del codigo
-> PROS: un solo codigo, no hay divergencias.
-> CONS: eficiencia


Cual seria la mejor en un escenario tan hipotetico ? gracias por su tiempo.

(me estoy orientando por crear una clase aparte encargada exclusivamente de las busquedas pero requeriria algo mas de refactoring ... sera que es una perdedera de tiempo ?)
__________________
Salu2!

Última edición por Italico76; 07/08/2013 a las 19:34
  #2 (permalink)  
Antiguo 07/08/2013, 19:44
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 10.106
Antigüedad: 15 años, 8 meses
Puntos: 2237
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Sin ver específicamente lo que tienes y, suponiendo que estás hablando de consultas a base de datos, yo pensaría en una función para establecer los filtros necesarios y otra para ejecutar la consulta, de forma que:

Código PHP:
Ver original
  1. $filter = $this->findFilter('/*A o no-A, B o no-B, etc. */);
  2. $records = $this->find($filter);

Incluso podrías agregar otros parámetros en find() para paginación (offset, limit) y orden (ORDER BY).
__________________
- León, Guanajuato
- GV-Foto
  #3 (permalink)  
Antiguo 07/08/2013, 19:51
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Hola amigo Triby ... que pena no haber colocado el codigo..... no hay base de datos en el asunto... mira coloco algo de codigo ahora :)

A/no-A seria con / sin GAPs y ...
B/no-B seria con deep_search en TRUE/FALSE

Código PHP:
Ver original
  1. public function findSubNoGaps(TagSequence $sub, $deep_search=null)
  2.     {      
  3.  
  4.         // obtener la primera ocurrencia con Find() y a partir de ahi recorrer CONTINUO $sub comparando uno contra uno cada tag, si falla..... chequear cuanto queda por recorrer de $this y si es > long($sub) entonces volver a buscar la primera ocurrencia con Find() y repetir el proceso
  5.  
  6.         // rebobinar las secuencias aguja y pajar es responsabilidad del programador !!! no se hara aqui!    
  7.        
  8.         if ($this->length()==0 || $sub->length()==0)
  9.             Throw new \LengthException('Aguja o pajar no pueden estar vacios');
  10.        
  11.        
  12.         if ($this->length(true) < $sub->length(true))
  13.             Throw new \LengthException("Aguja no puede ser mayor que pajar");
  14.        
  15.                
  16.             $count = 0;
  17.             $tag = $this->current();
  18.             $tagSub = $sub->current();    
  19.          
  20.  
  21.             // while ext.
  22.             while ($this->valid() && $sub->valid() && ($this->length()- $this->key() >= $sub->length())  )
  23.             {
  24.                 #echo "Entrando WHILE EXTERIOR<p/>";
  25.                $count = 0;
  26.                 $sub->rewind();
  27.  
  28.                 $tagSub = $sub->current();
  29.                        
  30.                 $found = ($this->find($tagSub)>=0);
  31.                 if ($found){
  32.                     $tag = $tagSub;
  33.                     $count = 1;
  34.                 }
  35.                
  36.                 if (is_null($this->key()))
  37.                 {
  38.                     #echo "Cursor de secuencia pajar fuera de rango sin coincidencias!";
  39.                    return false;              
  40.                 }
  41.  
  42.                 #echo 'Sub buscado : '.$sub->key().' ] -- '; echo $sub->current()->getElementName(); echo '<p/> En Pajar: '.$this->key().' ] -- '; echo $tag->getElementName(); var_dump($found); echo '---------------<p/>';
  43.  
  44.                 // while int.
  45.                 while ($found && $this->valid() && $sub->valid())
  46.                 {                                
  47.                  
  48.                     $tagSub = $sub->next();  
  49.                     $tag = $this->next();                          
  50.                
  51.                     $found = ($tag->compareTo($tagSub)>=0);
  52.  
  53.                     if ($found)
  54.                         $count++;          
  55.          
  56.                     // solo para debug:  
  57.                     if ($this->valid() && $sub->valid())
  58.                     {
  59.                         #echo 'Sub buscado : '.$sub->key().' ] -- '; echo  $tagSub->getElementName(); echo '<p/> En Pajar: '.$this->key().' ] -- '; echo $tag->getElementName(); var_dump($found); echo '---------------<p/>';
  60.                    }
  61.  
  62.                
  63.  
  64.                 } // endWhile int.
  65.  
  66.             } // endWhile ext.
  67.  
  68.             #echo "<p/><i>Count = $count </i>";
  69.  
  70.             return ($count == $sub->length());
  71.            
  72.     }


Código PHP:
Ver original
  1. public function findSubWithGaps(TagSequence $sub, $deep_search=null)
  2.     {
  3.             // Asumo puede haber "gaps"
  4.             // por eso busco con find() en vez de avanzar e ir comparando
  5.  
  6.             // Deberia tener en cuenta que tags no-pueden aparecer en los Gaps, longitud minima y maxima permitida, etc.  
  7.            
  8.         if ($this->length()==0 || $sub->length()==0)
  9.             Throw new \LengthException('Aguja o pajar no pueden estar vacios');
  10.        
  11.        
  12.         if ($this->length(true) < $sub->length(true))
  13.             Throw new \LengthException("Aguja no puede ser mayor que pajar");
  14.  
  15.             $tag = $this->current();
  16.             $tagSub = $sub->current();
  17.  
  18.             #echo "<h1>[ {$this->key()} ] $tag</h1><p/>";
  19.            #echo "<h1>[ {$sub->key()} ] $tagSub</h1><p/>";
  20.            
  21.             $count = 0;
  22.        
  23.             $found = ($this->find($tagSub)>=0);
  24.             if ($found)
  25.                 $tag = $tagSub;
  26.  
  27.             echo 'Sub buscado : '.$sub->key().' ] -- '; echo $sub->current()->getElementName(); echo '<p/> En Pajar: '.$this->key().' ] -- '; echo $tag->getElementName(); var_dump($found); echo '---------------<p/>';
  28.  
  29.             while ($found && $this->valid() && $sub->valid())
  30.             {
  31.                 $count++;              
  32.                  
  33.                 $tagSub = $sub->next();                            
  34.                
  35.                 $found = ($this->find($tagSub)>=0);
  36.                 if ($found)
  37.                         $tag = $tagSub;
  38.  
  39.                 $tag = $this->current();
  40.  
  41.  
  42.                 // solo para debug:  
  43.                 if ($this->valid() && $sub->valid())
  44.                 {
  45.                     echo 'Sub buscado : '.$sub->key().' ] -- '; echo $tagSub->getElementName(); echo '<p/> En Pajar: '.$this->key().' ] -- '; echo $tag->getElementName(); var_dump($found); echo '---------------<p/>';
  46.                 }
  47.  
  48.                
  49.  
  50.             } // endWhile
  51.  
  52.             echo "<p/><i>Count = $count </i>";        
  53.            
  54.  
  55.             return ($count == $sub->length());
  56.  
  57.     }


Como veras..... esas dos funciones son bastante diferentes excepto por algunos chequeos de tipo Runtime ... pero en ambas debo ahora agregar la parte de DEEP_SEARCH que seria si quiero que las busquedas se hagan lineales o como un DomNodeList donde hay una "profundidad" involucrada y... eso se podria hacer metiendo algunos IF aqui y alla en ambas dos funciones......

Entonces.... hago de las dos funciones solo una ? hago de esas dos, cuatro ? las coloco como clase aparte especializada en busquedas ? etc ... :P

Mil gracias!
__________________
Salu2!
  #4 (permalink)  
Antiguo 07/08/2013, 20:24
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 10.106
Antigüedad: 15 años, 8 meses
Puntos: 2237
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Tal vez sí amerite la creación de una clase y desde el constructor, o un método específico para establecer configuración, realizar las verificaciones de aguja/pajar.

Luego, un método público find() para ejecutar cualquiera de las 4 búsquedas donde identifiques si es gap/no-gap, deep/no-deep y ejecutes el método privado que corresponda a esa configuración, findNoGap(), findWithGap(), etc.

Seguramente habrá duplicidad de código, pero lo tendrás en una clase aparte y podrás ejecutar las búsquedas con un sólo método.

Habría cosas a considerar como crear una sola instancia para todas las búsquedas, con lo que en find() se realizará también la verificación de aguja y pajar.
__________________
- León, Guanajuato
- GV-Foto
  #5 (permalink)  
Antiguo 07/08/2013, 21:01
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Gracias por tu tiempo amigo @Triby

Creerias estas en lo correcto
__________________
Salu2!
  #6 (permalink)  
Antiguo 08/08/2013, 01:50
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 10 años, 9 meses
Puntos: 379
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Cita:
Como veras..... esas dos funciones son bastante diferentes excepto por algunos chequeos de tipo Runtime ... pero en ambas debo ahora agregar la parte de DEEP_SEARCH que seria si quiero que las busquedas se hagan lineales o como un DomNodeList donde hay una "profundidad" involucrada y... eso se podria hacer metiendo algunos IF aqui y alla en ambas dos funciones......

Entonces.... hago de las dos funciones solo una ? hago de esas dos, cuatro ? las coloco como clase aparte especializada en busquedas ?
Según veo estas tratando de implementar algoritmos de búsqueda como objetos y quieres que el cliente pueda intercambiar estos objetos de acuerdo a ciertas condiciones. De ser así usa el patrón Strategy: http://sourcemaking.com/design_patterns/strategy
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #7 (permalink)  
Antiguo 08/08/2013, 08:28
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Cita:
Iniciado por hhs Ver Mensaje
Según veo estas tratando de implementar algoritmos de búsqueda como objetos y quieres que el cliente pueda intercambiar estos objetos de acuerdo a ciertas condiciones. De ser así usa el patrón Strategy: http://sourcemaking.com/design_patterns/strategy
Gracias HHS... llegue a pensar en el patron pero como por el momento puedo decir que son solo 4 variaciones del algoritmo... hice algo mas simple (una clase estatica con las variaciones) aunque si llegaran a dispararse el numero de variaciones ya seria imprescindible esa solucion.

Es asi, cierto ? no justifica si puedes acotar a unas pocas... o sera que si ?
__________________
Salu2!
  #8 (permalink)  
Antiguo 10/08/2013, 01:02
Avatar de hhs
hhs
Colaborador
 
Fecha de Ingreso: junio-2013
Ubicación: México
Mensajes: 2.995
Antigüedad: 10 años, 9 meses
Puntos: 379
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Cita:
Iniciado por Italico76 Ver Mensaje
Gracias HHS... llegue a pensar en el patron pero como por el momento puedo decir que son solo 4 variaciones del algoritmo... hice algo mas simple (una clase estatica con las variaciones) aunque si llegaran a dispararse el numero de variaciones ya seria imprescindible esa solucion.

Es asi, cierto ? no justifica si puedes acotar a unas pocas... o sera que si ?
Simple no siempre es la mejor solución y el error mas común es pensar que tiene que haber un problemas mas complejo para aplicar un principio o patrón de diseño.
Es probable que estés usando una clase estática por que miras tus algoritmos de búsqueda en términos de procedimientos y no de objetos. El detalle con esto es que en algún momento el objeto que va a usar tu clase estática tiene que decidir que método ocupar para su búsqueda y eso se traduce en una serie de if o en el uso de un switch, si usas el patrón puedes quitar la ronda de condiciones y simplificar el uso de tus algoritmos. te recomiendo la siguiente lectura: http://www.informit.com/articles/art...98607&seqNum=2
__________________
Saludos
About me
Laraveles
A class should have only one reason to change.
  #9 (permalink)  
Antiguo 10/08/2013, 07:09
Avatar de dashtrash
Colaborador
 
Fecha de Ingreso: abril-2007
Ubicación: Ni en Sevilla,ni en Sanlúcar..qué más da..
Mensajes: 927
Antigüedad: 17 años
Puntos: 270
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Los sistemas de búsqueda/ordenación son buenos candidatos para hacerlos genéricos, incluso sin OOP. La función uasort() permite especificar un callback de comparación de objetos.De esta forma puedes ordenar cualquier tipo de objetos.
Hablando en "genérico", cualquier búsqueda va a necesitar sólo un método que diga si A==B.
Lo que quiero decir con esto, es que una posibilidad es crear una clase de búsquedas genérica, que permita buscar sobre cualquier lista de objetos que implemente una interfaz que define un método "isEqualTo". Es posible que también, para cierto tipo de búsquedas (binarias,etc), se requiera que el método devuelva <0 , 0 , o >0 , lo cual es el típico estándar de este tipo de funciones.
  #10 (permalink)  
Antiguo 11/08/2013, 08:22
Avatar de Italico76  
Fecha de Ingreso: abril-2007
Mensajes: 3.303
Antigüedad: 17 años
Puntos: 292
Respuesta: Duda diseño : entre re-uso / eficiencia / evitar divergencias

Gracias a todos......

Cita:
Iniciado por hhs Ver Mensaje
El detalle con esto es que en algún momento el objeto que va a usar tu clase estática tiene que decidir que método ocupar para su búsqueda y eso se traduce en una serie de if o en el uso de un switch, si usas el patrón puedes quitar la ronda de condiciones y simplificar el uso de tus algoritmos. te recomiendo la siguiente lectura: http://www.informit.com/articles/art...98607&seqNum=2
El "Contexto" no es simple sino formado por estados de varias variables ........creeria o hay en algun lado una serie de IFs / SWITCH-CASEs o bien accedo a un arreglo multi-dimesional que guarda el nombre del metodo o clase de busqueda.......... Si estoy equivocado dame un ejemplo de implementacion pero es por el caso particular de un contexto complejo que no veo el patron por si mismo resuelva el asunto. Distinto seria se pudiera hablar de un contexto por ejemplo de suma / resta / division / multiplicacion / etc......

Sobre lo que dices tu @Dashboard...... tengo implementada IComparable como en C#, no puedo hacer dibujitos UML pero dejo las interfaces por si ven algo mal......

Código PHP:
Ver original
  1. /**
  2.  * Interfaces
  3.  *
  4.  * @package FastDev\Sequences
  5.  * @author Pablo Bozzolo (2013)
  6.  *
  7.  */
  8.  
  9. /**
  10.  * IComparable: interfaz homologa a C# 
  11.  */
  12. Interface IComparable
  13. {
  14.    /**
  15.     * @param <type> algo comparar  
  16.     * @return int {-1,0,1}
  17.     */
  18.    public function compareTo($other);
  19.  
  20. }
  21.  
  22. Interface IElement extends IComparable { }
  23.  
  24. Interface ISequenceable extends IComparable, \Iterator, \Serializable
  25. {
  26.     public function length();    
  27.     public function addElem (IElement $tag);
  28.     public function findElem (IElement $search, $continue=true);    
  29.     public function findSub(ISequenceable $sub);
  30. }
  31.  
  32.  
  33. Interface IGap extends ISequenceable { }
  34.  
  35. /**
  36.  * Secuencias que pueden contener Gaps
  37.  */
  38. Interface IGapSequenceable extends ISequenceable
  39. {
  40.     public function length($include_gap_length=false);
  41.     public function compareTo ($sec, $gaps=null);
  42.     public function haveGaps();
  43.     public function addGap (IGap $gap);
  44.     public function addElem (IElement $tag);
  45.     public function findElem (IElement $search, $continue=true);    
  46.     public function findSub(ISequenceable $sub, $gaps=null);
  47. }
  48.  
  49. /**
  50.  * Chequeos de concistencia
  51.  */
  52. Interface IChecking
  53. {
  54.     public function getMinLen();
  55.     public function getMaxLen();
  56.     public function getMustContain();
  57.     public function getMustNotContain();
  58.     public function getCanContain();
  59.     public function countMustContain();
  60.     public function countMustNotContain();
  61.     public function countCanContain();
  62.     public function setMinLen(int $len);
  63.     public function setMaxLen(int $len);
  64.     public function addCanContain(IElement $e);
  65.     public function addMustContain(IElement $e);
  66.     public function addMustNotContain(IElement $e);
  67.     // y chequeo con:
  68.     public function check();
  69. }
  70.  
  71.  
  72. /**
  73.  * Secuencias que pueden contener Gaps pero ademas profundidad (listas de nodos)
  74.  */
  75. Interface ITagSequenceable extends IGapSequenceable
  76. {  
  77.     public function getDeep($pos=null);            
  78.     public function compareTo ($sec, $gaps=null, $deep=null);
  79.     public function addGap (IGap $gap, $deep=null);  
  80.     public function addElem (IElement $tag , $deep=null);    
  81.     public function findElem (IElement $search, $continue=true);        
  82.     public function findSub (ISequenceable $sub, $deep=null, $gaps=null);
  83. }
  84.  
  85.  
  86. Interface ISequenceAligneable
  87. {
  88.     public static function add (ISequenceable $sec);
  89.     public static function align();
  90. }

Voy a usar la libreria para hacer comparaciones, busquedas y alineamientos de secucuencias de HTML / XML, ADN, ARN y proteinas.......

Es muy facil buscar una secuencia dentro de otra, aun si la secuencia es un arbol DOM exportado como DomNodeList
__________________
Salu2!

Última edición por Italico76; 11/08/2013 a las 23:51

Etiquetas: diseño, eficiencia
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 02:15.