Herencia y extensión de objetos con JavaScript

Si está familiarizado con la programación orientada a objetos, lo más probable es que esté familiarizado con las subclases y la herencia. Sin embargo, la herencia ha estado recibiendo una mala reputación. Creo que esto se debe a que algunos desarrolladores lo ven como una solución para todos cuando necesitas modificar un programa. El problema con esto es que las jerarquías de clase pueden volverse inmanejables. 

Hay otros patrones de diseño que podemos usar para hacer que nuestras aplicaciones sean más fáciles de entender y estén listas para el cambio. Te mostraré ejemplos de cómo puedes usar la herencia y el decorador y el patrón compuesto para mejorar el diseño de tu programa..

Herencia

La idea detrás de la herencia es que un objeto "es una" versión especializada de otro objeto. Existe una clase padre (también conocida como superclase) que define las propiedades básicas de nuestro objeto. Y hay una clase secundaria (subclase) que hereda las propiedades de la clase principal. 

Un ejemplo de herencia es un perro y un caniche. Todos los perros tienen ciertas características como cuatro patas y la capacidad de ladrar. Un caniche "es un" tipo de perro. Un SUV es un vehículo. Un círculo es una forma. Así es como se vería nuestra jerarquía de clases si estuviéramos diseñando un programa para crear formas.

La ventaja de tener una clase Shape es que podemos reutilizar las propiedades y los métodos que definimos en otras clases.. 

Tenga en cuenta que el getArea El método fue redefinido en cada una de nuestras subclases. No tuvimos que redefinir este método, pero lo hicimos para reemplazar la implementación del método por parte de los padres. Esto se debe a que cada forma tendrá su propia forma de calcular el área.. 

Anular un método padre en una clase secundaria es un ejemplo de polimorfismo. El polimorfismo es la capacidad de los objetos para tener múltiples formas. Permite que las subclases tengan métodos con el mismo nombre que su superclase pero con diferentes implementaciones.  

Este es un ejemplo de cómo se vería nuestro código para crear una subclase de Forma y Círculo:

clase Shape constructor (x, y) this.xPosition = x; this.yPosición = y;  getArea () … clase El círculo extiende la Forma constructor (x, y, radio) super (x, y, radio); this.radius = radio getArea () … let circle = new Circle (1,2,3);

Uno de los inconvenientes de esta opción de diseño es que si decide que la clase principal debe cambiar, entonces es posible que las subclases también deban cambiar, junto con todos los objetos que creamos.. 

Por ejemplo, supongamos que luego decidimos que sería mejor reemplazar los parámetros x e y de la clase Shape con un objeto. En consecuencia, tendríamos que cambiar el constructor para todas nuestras subclases y los argumentos para cada objeto que instanciamos.

Podemos ver cómo esto puede convertirse fácilmente en problemático. Tendríamos que asegurarnos de que obtuviéramos el diseño correcto la primera vez para evitar el cambio. Pero eso no es práctico, ni es por lo que debemos luchar. Un programa es una entidad en constante evolución, y es mejor para nosotros los desarrolladores si tenemos la flexibilidad de realizar cambios fácilmente. Como mínimo, no deberíamos tener más de un nivel de clases para niños.

Patrón decorador

Un decorador nos permite adjuntar propiedades a un objeto después de que se hayan creado. Esto significa que podemos agregar funcionalidad sin subclasificar o preocuparnos por la implementación de nuestro objeto. 

En lugar de pensar que un círculo es una forma, podríamos usar la clase Forma para crear círculos y envolverlos con las propiedades adicionales que deseamos. Aquí hay una alternativa para crear objetos circulares usando un decorador:

clase Shape constructor (datos) this.x = data.x; this.y = data.y;  getArea () … funciona CircleDecorator (shape) shape.radius = 3; shape.getArea = function () …; forma de retorno  let shape = new Shape (x: 1, y: 2); Let circle = new CircleDecorator (shape);

Podemos agregar o modificar miembros de nuestra clase Shape con un decorador en lugar de subclasificarlos. Con nuestro ejemplo de formas, es posible que solo desee crear un objeto de círculo que tenga todas las propiedades que necesita y haga lo mismo para otras formas. Eso está bien. Pero un decorador nos permite reutilizar el código en nuestra clase de Forma y modificarlo con la funcionalidad que difiere con cada forma. Como resultado, tendremos más objetos, pero más objetos son más fáciles de administrar que más subclases.

Este patrón no se limita a la creación de gráficos. Puede usarlo en cualquier situación en la que desee agregar responsabilidades a un objeto. 

Por ejemplo, es posible que tengamos una clase que maneje el registro de usuarios en nuestra cuenta. Antes de guardar su información en nuestra base de datos, sería conveniente verificar que la entrada sea válida y no contenga ningún script malicioso. Podríamos decorar la clase con un método para validar la información primero. Este mismo decorador puede ser reutilizado en cualquier lugar de nuestra aplicación donde aceptamos comentarios del usuario..

Patrón compuesto

Los objetos pueden estar compuestos de otros objetos. La vista para una aplicación se puede considerar como un componente que se compone de otras vistas. Si estuviéramos haciendo un juego, nuestro mundo de juego mostraría todos nuestros gráficos que creamos como círculos y cuadrados. Cada vez que actualizamos nuestra vista, deberíamos volver a dibujar cada elemento. Necesitamos una forma de gestionar todos los elementos como grupo.. 

Ahí es donde el patrón compuesto puede ayudarnos. Podemos crear una clase que sea responsable de todos los elementos. Cuando queremos volver a dibujar los elementos, llamamos al método de dibujo de esta clase, y llamará al método de dibujo en cada elemento individual..  

clase Componente constructor (nombre) this.components = []; this.element = document.createElement (name);  agregar (elem) this.components.push (elem);  draw () for (const elem of this.components) elem.draw ();  clase Circle constructor (datos) this.x = data.x; this.y = data.y; this.radius = data.radius;  getArea () … draw () … let world = new Component ('div'); let circle = new Circle (x: 1, y: 1, radio: 2); sea ​​circle2 = new Circle (x: 10, y: 10, radio: 2); world.add (círculo); world.add (circle2); world.draw ();

Una página web también puede considerarse como un componente. Este componente podría tener un menú, una barra lateral y una publicación de blog. La publicación sería un subcomponente que tiene una imagen, un título y un cuerpo. los dibujar El método para nuestro componente principal de la aplicación llamará a dibujar en el menú, la barra lateral y la publicación. El componente de la publicación, a su vez, llamará a la imagen, el título y el cuerpo de la publicación.. 

Aquí hay una vista de lo que a una página web le gustaría dividir en componentes:

Este patrón no se limita a la creación de vistas. Por ejemplo, si estuviéramos haciendo un juego, podríamos tener un componente para administrar los elementos en la pantalla, un componente para administrar el audio y un componente para administrar el estado del juego.. 

Todos estos estarían dentro de un componente que llamo el motor del juego. El motor del juego tendría un método de inicialización que llamaría el método de inicialización en cada uno de sus subcomponentes. Ese es el poder en el uso del patrón compuesto. En lugar de tratar con objetos individuales, podemos tratarlos como un solo objeto..  

Conclusión

La herencia nos permite reutilizar el código definiendo un objeto en términos de otro objeto. El patrón decorador nos permite agregar responsabilidades a un objeto sin cambiar el código original o subclases. El patrón compuesto modela relaciones parte-todo. Estos patrones no están destinados a ser utilizados de forma aislada. 

JavaScript se ha convertido en el lenguaje de trabajo en la web. No deja de tener sus curvas de aprendizaje, y también hay muchos marcos y bibliotecas para mantenerte ocupado. Si está buscando recursos adicionales para estudiar o usar en su trabajo, vea lo que tenemos disponible en Envato Market.

Se pueden combinar como mejor le parezca. Los ejemplos que proporcioné tampoco deben tomarse como la única aplicación para usar los patrones. Son solo una guía. Siéntete libre de usar tu creatividad para aplicarlos. No hay una manera de implementarlas o un caso de uso..