SOLID

 defectos que causan daño al sw:

-poner mas codigo/funcionalidad no relacionada en una unica clase

-hacer depender una clase de otra (estrechamente acopladas) el cambio en una afectará a la otra

-meter codigo duplicado

soluciones:

-elegir arquitectura correcta (mvc,etc)

-seguir principios de diseño ...solid

-elegir patrones de diseño

--------------------------------------------

SOLID

-acrónimo: cada letra representa un principio. 

-si se sigue hará de nuestro sw uno escalable en el tiempo.

-tiene una relación con los conceptos de:

alta cohesión y bajo acoplamiento

alta cohesión: la información que almacena una clase debe ser coherente y estar relacionada con la clase.

bajo acoplamiento: tener las clases lo menos ligadas entre si. de tal modo que si se modifica una de ellas, no afecte o afecte poco al resto de clases.


SOLID, principios:

S: responsabilidad única

0: abierto o cerrado

L: sustitución de Liskov

I: segregación de interfaces

D: inversión de dependencia


un buen diseño nos ayuda a hacer más sencillo el mantenimiento del sw, para que cada vez que nos pidan una nueva funcionalidad no tener que estar tocando media aplicación de código antiguo.

reducimos así el costo de mantenimiento de sw.


Principio de Responsabilidad Unica:

-cada modulo de sw debe tener una sola razón para cambiar (no como una navaja suiza)

ejemplo

class Usuario{

public function pagarMisDeudas(){

  if(tieneDineroEnELBanco(id_usuario){

...

}


}

public function tieneDineroEnELBanco(id_usuario){

...

}

}

-----------------------

la responsabilidad de la funcion tieneDineroEnELBanco(id_usuario)

 no le pertenece directamenreal Usuario...

pues esa misma logica la vamos a querer usar en otra parte de la aplicacion y terminemos copiando y pegando ese codigo, haciendo luego inmantenible.

entonces, una solución sencilla sería:

class Usuario{

Banco $banco;

public Usuario(Banco banco){

     $this->banco = banco;

}

public function pagarMisDeudas(){

  if($this->banco->tieneDineroEnELBanco(id_usuario){

...

}


}

Principio Abierto Cerrado

un modulo o clase de sw está abierto para extensión cerrado para modificación.


entonces si por ejemplo tenemos

class AreaService{

  public sumarAreas(Rectangulo[] rectangulos){
    //recorremos el arreglo de rectangulos ,
    /por cada rectangulo, segun su base y altura y calculamos el area y lo acumulamos en una variable
   //devolvemos el valor de la variable de acumulacion
  }
}

si ahora tambien ademas de rectangulos tenemos circulos, 
una solución podria ser
hacer una clase Figura de la cual extender Rectangulo y Circulo
entonces
modificamos el metodo
  public sumarAreas(Figura[] figura){
    //recorremos el arreglo de figuras ,
    /por cada figura, segun la instancia de què objeto sea calculamos su area y lo acumulamos en una variable
   //devolvemos el valor de la variable de acumulacion
  }
pero que pasa si se agregan mas tipos de Figura?

entonces tendriamos que modificar el metodo de sumarAreas para poder calcular el area
segun cada uno de los nuevos tipos de figuras.

se viola lo de "cerrado para modificación" del método..
entonces lo que se puede hacer es que el método que calcula el área debe estar implementado en cada una de las clases y ser llamadas  dentro del mètodo de sumarAreas

PRINCIPIO DE LISKOV

asegurarse de que la clase derivada no modifique el comportamiento de la clase padre.


class FileManager{
   writeFiles(File[] file){
      file->write();
   }
}

donde File tiene 2 metodos: read y write

si luego, nos indican que hay Files que no pueden escribirse.

se podria crear FileReadeable para que extiendan de File y reescriba el metodo write
donde el metodo write de FileReadeable lance una exception.

esto viola el principio, ya que el hijo ya no hace lo del padre.


entonces lo que vamos a hacer es crear 2 interfaces

IFileReadeable con el unico metodo read
IFileWritable con el unico metodo write


donde File implementaria ambas interfaces

entonces, FileManager quedaria asi:

class FileManager{
   writeFiles(IFileWriteable[] file){
      file->write();
   }
}


principio de Segregación de Interfaces

es preferible muchas interfaces con pocos metodos
que pocas con muchos.
asi no obligamos a un cliente a implementar metodos que no usa.

por ejemplo
tenemos que una emplresa hay un TeamLead que puede crear una tarea, asignar una tarea y trabajarenunatarea.
entonces podemos crear la interface ILead
con los metodos 
createTask()
assignTask()
WorkOnTask()

y luego creamos la clase TeamLead que implementa ILead

luego nos dicen que hay un Manager con similares capacidades que el TeamLead pero que no puede trabajar en ninguna tarea,
entonces podemos crear una clase Manager que implemente ILead
y en el metodo workOnTask() que lance una excepcion indicando un error.

esta soluciòn viola el principio, pues se està obligando a Manager a implementar un método que no usa.
ahora imaginemos que tambien tenemos un programador que solo puede trabajar en una tarea,

lo que tendriamos que hacer es crear 3 interfaces

IProgrammer con el metodo workOnTask()
IManager con el metodo createTask() y assignTask()

entonces :
La clase TeamLead implementa IProgrammer y IManager
La clase Programmer implementa IProgrammer
La clase Manager implementa IManager

Principio de inversión de dependencias


Los modulos/clases de alto nivel no deberian depender de las de bajo nivel.

supongamos que tenemos
class Logger{
   logMessage(string message){
  }
}
class DBLogger{
  logMessage(string message){
 }
}

y tenemos una 
class ExceptionLoggerManager{
logearEnFile(Exception e){
  log =new FileLoger()
  log->logMessage(e->getMessage())
}
logearEnDB(Exception e){
}
  log = new DBLoger();
  log->logMessage(e->getMessage())

}

class exportarData(){
 try{
}catch(IOException e){
new ExceptionLogerManager->logearEnDb(e);
}catch(Exception e){
new ExceptionLogerManager->logearEnFile(e)
}

}

el problema aca es que cada vez que nos pidan logear en otro lado, la clase ExceptionLogerManager
va a tener que modificarse. Eso pasa porque depende mucho de clase de bajo nivel.

la solucion:
creamos una interface ILoger metodo log(string)
y cada log distinto que la implemente
entonces

la nueva interfaz se pasa como parametro en el constructor de la clase ExcpetionLogerManager

class ExceptionLogerManager{

ILoger _iloger;

ExceptionLogerManager(Iloger iloger)
{
_iloger = iloger;
}

}
 entonces ahora la clase de exportar quedaria asi:

class exportarData(){
 try{
}catch(IOException e){
new ExceptionLogerManager(new DBLOger())->log(e);
}catch(Exception e){
new ExceptionLogerManager(new FIleLOger())->loge(e)
}

}





 

No hay comentarios:

Publicar un comentario

linux ubuntu mint actualizar chrome

 desde una terminal: $ sudo apt update $ sudo apt install google-chrome-stable