SOLID los primeros 5 principios del diseño orientado a objetos con JavaScript

SOLID Significa los primeros cinco principios de diseño orientado a objetos de Robert C.Martin .

Los principios SOLID se pueden utilizar para diseñar y desarrollar software extensible y fácil de mantener. Al utilizar estos principios en la programación orientada a objetos, los desarrolladores pueden crear y mantener la base de código muy fácilmente.

SOLID significa:

  • Principio de responsabilidad única
  • Principio abierto-cerrado
  • Principio de sustitución de Liskov
  • Principio de segregación de interfaz
  • Principio de inversión de dependencia

En este artículo, aprenderemos sobre el principio del código base.

Principio de responsabilidad única

Una clase debe tener un solo trabajo.

Este principio establece y recomienda que una clase debe tener una sola responsabilidad. Si una clase contiene múltiples responsabilidades, entonces se acopla. El acoplamiento crea una cadena de dependencia que nunca es buena para el software.

Este principio también se aplica al diseño de microservicios, donde asignamos una responsabilidad a un servicio.

Por ejemplo, considere esta clase:

class SuperHero {

    constructor
( nombre : cadena ) { }

    getHeroName
( ) { }

    saveHeros
( a : Hero ) { }
}

Esta clase viola SRP. He aquí por qué.

Esta clase tiene más que responsabilidad. Gestiona las propiedades de los superhéroes y también gestiona la base de datos. Si hay alguna actualización en las funciones de administración de la base de datos, también afectará las funciones de administración de propiedades, lo que resultará en un acoplamiento.

Para cumplir con el SRP, simplemente creamos otra clase que manejará la responsabilidad exclusiva de la administración de la base de datos.

class SuperHero {

    constructor
( name : string ) { }

    getHeroName
( ) { }
}

class SuperHeroDB {

    getHeros
( a : Hero ) { }

    saveHeros
( a : Hero ) { }
}

De esta manera, nuestro código se vuelve más cohesivo y menos acoplado.

Principio abierto-cerrado

Las entidades de software (clases, módulos, funciones) deben estar abiertas para extensión, no modificación.

Esto simplemente significa que las clases, funciones no deben modificarse siempre que necesitemos desarrollar nuevas características. Debemos ampliar las entidades, no modificarlo .

Aprendamos esto con la clase de nuestro superhéroe.

class SuperHero {

    constructor
( nombre : cadena ) { }

    getHeroName
( ) { }
}

Queremos recorrer una lista de superhéroes y devolver el arma que elijan.

class SuperHero {

    constructor
( name : string ) { }

    getHeroName
( ) { // …}
 

    getWeapons
( herosName ) {
      for ( let index = 0 ; index <= herosName. length ; index ++ ) {
         if ( herosName [ index ] . nombrar === ‘Thor’ ) {

            consola.
log ( ‘rompe tormentas’ ) ;
         }
         if ( herosName [ index ] . name === ‘captainamerica’ ) {

            consola.
log ( ‘Escudo’ ) ;
         }
      }
    }

}

La función getWeapons () no cumple con el principio abierto-cerrado porque no se puede cerrar contra nuevos tipos de superhéroes.

si agregamos un nuevo superhéroe, digamos Iron man. Entonces necesitamos cambiar la función y agregar el nuevo código como este.

class SuperHero {

    constructor
( name : string ) { }

    getHeroName
( ) { // …}
 

    getWeapons
( herosName ) {
      for ( let index = 0 ; index <= herosName. length ; index ++ ) {
         if ( herosName [ index ] . nombrar === ‘Thor’ ) {

            consola.
log ( ‘rompe tormentas’ ) ;
         }
         if ( herosName [ index ] . name === ‘captainamerica’ ) {

            consola.
log ( ‘Escudo’ ) ;
         }
         if ( herosName [ índice ] . nombre === ‘ironman’ ) {

            consola.
log ( ‘el traje’ ) ;
         }
      }
    }

}

Si observa, por cada nuevo superhéroe, se agrega una nueva lógica a la función getWeapons (). Según el principio abierto-cerrado, la función debe estar abierta para extensión, no modificación.

Así es como podemos hacer que la base de código cumpla con el estándar de OCP.

class SuperHero {

    constructor
( nombre : cadena ) { }

    getWeapons
( ) { }
}

class Thor extiende SuperHero {

     getWeapons
( ) {          
        return ‘rompe tormentas’ ;
     }
}

clase CaptainAmerica extiende SuperHero {

     getWeapons
( ) {        
        return ‘Shield’ ;
     }
}

clase Ironmanextiende SuperHero {

     getWeapons
( ) {
        return ‘Traje’ ;
     }
}

función getWeapons ( a : Array < superhero > ) {
        for ( let index = 0 ; index <= a. length ; index ++ ) {

                console.
log ( a [ índice ] . getWeapons ( ) )
        }
}


getWeapons
( superhéroes ) ;

De esta manera no necesitamos modificar el código cada vez que se requiere agregar un nuevo superhéroe. Podemos simplemente crear una clase y extenderla con la clase base.

Principio de sustitución de Liskov

Una subclase debe ser sustituible por su superclase.

Este principio establece que cada subclase / clase derivada debe actuar como un sustituto de su clase base / padre.

Por ejemplo, considere este código.

class SuperHero {

    constructor
( nombre : cadena ) { }

    getWeapons
( ) { }
}

class Thor extiende SuperHero {

     getThorWeapons
( ) {          
        return ‘rompe tormentas’ ;
     }
}

clase CaptainAmerica extiende SuperHero {

     getCaptainWeapons
( ) {        
        return ‘Escudo’ ;
     }
}

clase Ironmanextiende SuperHero {

     getIronManWeapons
( ) {
        return ‘Traje’ ;
     }
}

función getWeapons ( a : Array < superhero > ) {
        for ( let index = 0 ; index <= a. length ; index ++ ) {

                console.
log ( un [ índice ] . getWeapons ( ) )
        }
}


getWeapons
( superhéroes ) ;

El código que se muestra arriba no se adhiere a LSP. Para hacerlo, necesitamos tener una función que esté en la clase base así como en la clase derivada, por lo tanto, la clase derivada actúa como un sustituto de su clase base.

class SuperHero {

    constructor
( nombre : cadena ) { }

    getWeapons
( ) { }
}

class Thor extiende SuperHero {

     getWeapons
( ) {          
        return ‘rompe tormentas’ ;
     }
}

función getWeapons ( a : Array < superhero > ) {
        for ( let index = 0 ; index <=una. longitud ; index ++ ) {

                consola.
log ( a [ índice ] . getWeapons ( ) )
        }
}


getWeapons
( superhéroes ) ;

Cuando se deriva una nueva clase, debe implementar la función getWeapons (), como esta.

clase Ironman extiende SuperHero {

     getIronManWeapons
( ) {
        return ‘Traje’ ;
     }
}

Principio de segregación de interfaz

Un cliente no debe verse obligado a depender de interfaces y métodos que no utilice.

Este principio establece que el cliente que usa la interfaz no debe verse obligado a usar los métodos que no necesita. Por ejemplo, considere esta interfaz.

Armas de interfaz {

    stormBreaker
( ) ;

    Escudo
( ) ;

    Martillo
( ) ;

    Traje
( ) ;
}

Esta interfaz tiene métodos que se ocupan de varias armas. Si alguna clase intenta usar este implemento, debe usar todos los métodos.

clase Thor implementa armas {

       rompe tormentas
( ) { }

       Escudo
( ) { }

       Martillo
( ) { }

       Traje
( ) { }
}

clase Ironman implementa armas {

       rompe tormentas
( ) { }

       Escudo
( ) { }

       Martillo
( ) { }

       Traje
( ) { }
}

Si agregamos un nuevo método en la interfaz, todas las demás clases deben declarar ese método o se lanzará un error. Para que la interfaz siga LSP, necesitamos segregar los métodos de armas en diferentes interfaces.

interfaz ThorWeapon {

    Hammer
( ) ;
}
interfaz IronmanWeapon {

    Suit
( ) ;
}
interfaz CaptainAmericaWeapon {

    Sheild
( ) ;
} la

clase thor implementa ThorWeapon {

    Hammer
( ) { // código}
}

Esto asegurará que el cliente solo esté implementando los métodos que debería usar.

Principio de inversión de dependencia

Dependa de abstracciones, no de concreciones.

Eso significa,

1. Los módulos de alto nivel no deben depender de los módulos de bajo nivel.
Ambos deberían depender de abstracciones.


2. Las abstracciones no deben depender de los detalles.
Los detalles deben depender de abstracciones.

Por ejemplo, considere este código:

piscina constante = mysql. createPool ( { // otros detalles});
class SuperHero {

   constructor
(base de datos privada : piscina ) { }

   saveHeroes
( ) {
      this . db . guardar ( ) ;
   }
}

Aquí, la clase SuperHero es un componente de alto nivel, mientras que una variable de grupo es un componente de bajo nivel. Esto viola el DIP. Para que se adhiera al principio, debemos realizar el siguiente cambio.

Conexión de interfaz {

  mysql.
createPool ( { // otros detalles})
}

class SuperHero {

   constructor
(base de datos privada : Conexión ) { }

   saveHeroes
( ) {
      this . db . guardar ( ) ;
   }
}

Con el pequeño cambio en el código anterior, podemos ver que tanto los módulos de alto nivel como los de bajo nivel dependen de la abstracción.

Conclusión

Aprendimos los cinco principios que todo desarrollador de software debe cumplir. Puede ser un poco aterrador al principio seguir todos estos principios, pero con la práctica y el cumplimiento constantes, se convertirá en parte de nosotros y tendrá un gran impacto en el mantenimiento de nuestra base de código.

Si tiene alguna pregunta / error / mejora, comente y hágamelo saber.

Estudio adicional

Implementación de inicio de sesión en Facebook con Nodejs y
los 5 mejores marcos de Node.js de Express para aumentar la productividad de codificación Las
15 mejores extensiones de código de Visual Studio para desarrollo web

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *