Sólidos principios de diseño en Kotlin | de Abhishek Saxena | diciembre 2022

Foto de Med Badr Chemmaoui en UnsplashAntes de entrar en el tema de los principios de diseño SOLID, debe comprender por qué los necesitamos en primer lugar. Si está escuchando el término SÓLIDO por primera vez, mantenga la calma porque está a punto de aprender una nueva forma de enseñar. Permítanme tratar de responder a la pregunta más importante. ¿Cuántos de ustedes realmente han sido retrasados? mal código? Cada uno de nosotros en algún momento. Si sabemos que el código incorrecto nos ralentiza, ¿por qué estamos escribiendo código incorrecto? Lo hacemos porque teníamos que ir rápido… y dejar que eso se hunda.

No conduces rápido apurándote. No vas rápido simplemente haciendo que funcione y dejándolo ir tan pronto como sea posible. quieres ir rápido Estás haciendo un buen trabajo. Te sientas con cuidado, piensas en el problema, escribes un poco, lo limpias y repites. Eso es rápido.

¿Cuáles son los síntomas del mal código?

  • Rigidez del códigoCodifique con dependencias en tantas direcciones que no puede realizar un cambio de forma aislada. Cambia parte del código y rompe la clase dependiente/llamadora y tiene que arreglarlo allí. Terminas haciendo cambios en 10 clases diferentes debido a ese único cambio.
  • fragilidad del códigoCuando realiza un cambio y se rompe el código no relacionado.
  • acoplamiento apretadoOcurre cuando una clase depende de otra clase.

Si puede relacionarse con cualquiera de los problemas anteriores, ¡entonces este artículo es para usted! En este artículo, aprenderemos cómo resolver estos problemas utilizando los principios de diseño SOLID. Los necesitamos para escribir.

  • código flexible
  • Código mantenible
  • código comprensible
  • El código puede tolerar cambios

SOLID es un acrónimo que representa 5 principios de diseño.

  • S — Principio de Responsabilidad Individual (PRS)
  • O — Principio abierto/cerrado (OCP)
  • L — Principio de sustitución de Liskov (LSP)
  • I — Principio de separación de la interfaz (ISP)
  • D — Principio de inversión de dependencia (DIP)

Un módulo debe tener una y sólo una razón para cambiar.

¿Qué es un módulo? La definición más simple es solo un archivo fuente. Sin embargo, algunos lenguajes y entornos de desarrollo no utilizan archivos fuente para contener su código. En estos casos, un módulo es solo un conjunto coherente de funciones y estructuras de datos.Fuente: Clean Architecture, Robert C. Martin

Antes de entender cómo se sigue/implementa/utiliza SRP, debemos entender cómo no se utiliza.Violación de SRP¿Puedes detectar la violación? El incumplimiento es que la Orden tiene más de una responsabilidad, es decir, hay más de una razón para un cambio.soluciónCree un pedido que se encargue de almacenar los datos del pedido. Cree un OrderNotificationSender que se encargue de enviar actualizaciones de notificaciones al usuario. Hemos extraído diferentes responsabilidades de la clase Order en clases separadas y cada una de ellas tiene una única responsabilidad. Opcionalmente, puede incluso ir un paso más allá y crear un OrderFassade que delegue responsabilidades a las clases individuales.Como podemos ver, cada clase tiene una única responsabilidad, siguiendo así el principio de responsabilidad única. El OCP fue acuñado en 1988 por Bertrand Meyer como

Un artefacto de software debe estar abierto a extensiones pero cerrado a modificaciones. En otras palabras, el comportamiento de un artefacto de software debería ser extensible sin tener que cambiar ese artefacto. Fuente: Arquitectura Limpia, Robert C. Martin

Violación de OCPPara comprender la violación de OCP, tomemos un ejemplo de un servicio de notificación que envía diferentes tipos de notificaciones: notificaciones automáticas y notificaciones por correo electrónico a los destinatarios.Supongamos que recibo una nueva solicitud y ahora admitimos notificaciones por SMS, lo que significa que necesito actualizar la enumeración de notificaciones y NotificationService para admitir notificaciones por SMS. Así que Notification y NotificationService serán asíEsto significa que cada vez que cambiamos el tipo de notificación, debemos actualizar el NotificationService para admitir el cambio. Esta es una clara violación de la OCP. Veamos cómo puedes apegarte al OCP.soluciónCree una notificación de interfaz. Cree las implementaciones de cada tipo de notificación: PushNotification y EmailNotification. Cree un servicio de notificación. Ahora su servicio de notificaciones sigue el OCP, ya que puede agregar/eliminar diferentes tipos de notificaciones sin cambiar el servicio de notificaciones. Cree una notificación por SMS que implemente la notificación. Como puede ver, agregué SMSNotification sin cambiar el NotificationService, siguiendo así el principio Abierto/Cerrado.

Nota al margen: este es el único principio que es realmente difícil de seguir y solo se puede cumplir por completo en un mundo ideal. Dado que no se puede lograr el cierre al 100%, el cierre debe ser estratégico.

En 1988, Barbara Liskov escribió lo siguiente para definir subtipos.

Si para cada objeto o1 de tipo S hay un objeto o2 de tipo T tal que para todos los programas P definidos por T el comportamiento de P permanece sin cambios cuando o2 es reemplazado por o1, entonces S es un subtipo de T.

En otras palabras, esto significa que el subtipo debería poder reemplazar al supertipo sin cambiar el comportamiento del programa. Tratemos de entender el principio considerando la violación del infame problema del cuadrado/rectángulo.Violación de LSPSabemos que un rectángulo es un polígono de 4 lados donde los lados opuestos son iguales y tienen un ángulo de 90°. Un cuadrado se puede definir como un tipo especial de rectángulo que tiene todos los lados de igual longitud. Si los cuadrados y los rectángulos siguieran LSP, entonces deberíamos poder sustituir uno por el otro.

Tenga en cuenta: el cuadrado y el rectángulo están escritos en Java porque el código de Kotlin mostraría claramente la infracción sin que yo lo pruebe.

Cree un controlador RectangleCreate SquareCreate para ejecutar el flujo. En el Code Driver anterior, podemos ver claramente que Rectangle y Square no pueden reemplazarse entre sí. Por lo tanto, LSP se viola claramente. Bajo ninguna circunstancia el problema anterior seguirá a LSP. Entonces, para la solución/ejemplo del LSP, veremos otro problema.Ejemplo de LSPConsidere un servicio de eliminación de desechos que procese diferentes tipos de desechos: desechos orgánicos y desechos plásticos.Create Waste interfaceCreate OrganicWaste y PlasticWaste que implementa Waste Interface.Create WasteManagementServiceCreate LSPDriverEn LSPDriver podemos ver claramente que podemos reemplazar diferentes tipos de residuos, es decir, orgánicos y plásticos, entre sí sin afectar el comportamiento del programa. Así es como se sigue el principio de sustitución de Liskov. El principio de segregación de interfaces establece que los desarrolladores no deben verse obligados a confiar en las interfaces que no están utilizando. En otras palabras, la clase que implementa la interfaz no debe verse obligada a usar los métodos que no necesita.Violación del ISPDigamos que creamos una biblioteca de interfaz de usuario con componentes y los componentes pueden tener diferentes interacciones de interfaz de usuario, p. B. Eventos de clic: un solo clic y un clic largo tienen este comportamiento, debe implementar la interfaz OnClickListener.Create OnClickListenerCreate CustomUIComponentPodemos ver claramente que CustomUICompoenent se ve obligado a anular el método onLongClick, aunque según los requisitos, no queremos que CustomUICompoenent tenga un comportamiento de clic prolongado. Esta es una clara violación de la LSP.soluciónEsta solución es sencilla, podemos separar la interfaz de OnClickListener en dos interfaces diferentes: OnClickListener y OnLongClickListener, que manejan el comportamiento de un solo clic y el comportamiento de clic largo respectivamente.Crear OnClickListener. Crear OnLongClickListener. Cree un componente de interfaz de usuario personalizado que implemente OnClickListener. Por lo tanto, siga el principio de separación de interfaces. El principio de inversión de dependencia establece que los sistemas más flexibles son aquellos en los que las dependencias del código se relacionan solo con abstracciones y no con concreciones. Para comprender este principio, debe saber a qué me refiero cuando digo que la clase A depende de la clase B. Salgamos un poco del camino para entender la línea de arriba. Digamos que tengo dos clases, clase A y clase B, el código está escrito de la siguiente maneraEn la línea 9 puede ver que se crea un objeto de ClassA y en la línea 10 se llama al método doSomething(). Dado que ClassB necesita un objeto de ClassA para funcionar correctamente, podemos decir que ClassA depende de ClassB. Usando DIP revertiremos esta dependencia.El diagrama anterior muestra DIP en acción, ya que invertimos la dependencia entre ClassA y ClassB, lo mismo se puede ver en el diagrama anterior. Ahora veamos el ejemplo para entender DIP.Un ejemplo donde las clases dependen unas de otrasDigamos que tenemos un NotificationService que solo envía un tipo de notificación, a saber, notificaciones por correo electrónico, ya que está estrechamente relacionado con la clase EmailNotification.Create EmailNotificationCreate NotificationServiceCreate NotificationDriverEl problema es que NotificationService depende de EmailNotification para enviar notificaciones. Aquí es donde entra en juego la dependencia. Necesitamos eliminar la dependencia de tal manera que NotificationService no dependa del tipo de notificación y debería poder enviar diferentes tipos de notificaciones.soluciónLa solución es bastante fácil ya que ya resolvimos este problema mientras analizamos OCP. Para que NotificationService sea independiente del tipo de notificación, debe depender de la clase abstracta o de una interfaz en lugar de la clase concreta, es decir, EmailNotification.Crear interfaz de notificación. Crear tipo de notificación: EmailNotification y SmsNotification. Crear servicio de notificaciones. Esto sigue el principio de inversión de dependencia. Todos los principios SOLID se pueden definir en una sola línea de la siguiente manera.

SRP: cada módulo de software debe tener una y solo una razón para un cambio. OCP: los sistemas de software deben ser fáciles de cambiar, deben diseñarse de modo que el comportamiento de estos sistemas pueda cambiarse agregando un nuevo código en lugar de cambiar el código existente LSP: para construir un sistema de software a partir de partes intercambiables, estas partes deben cumplir un contrato que permite que estas partes sean intercambiables.ISP: los diseñadores de software deben evitar depender de cosas que no usan.DIP: el código que implementa políticas de alto nivel no debe depender de detalles de bajo nivel. Fuente: Arquitectura Limpia, Robert C. Martin

Deja una respuesta

Tu dirección de correo electrónico no será publicada.