Análisis de patrones de diseño y principios de diseño: la importancia de crear código mantenible y escalable

Este artículo es compartido por la comunidad de la nube de Huawei " Análisis en profundidad de patrones y principios de diseño: la importancia de crear código escalable y mantenible " por Lion Long.

1. ¿Por qué necesitamos patrones de diseño?

1.1 Definición de patrón de diseño

Hay aproximadamente 23 patrones de diseño.

Los patrones de diseño se refieren a soluciones comprobadas a problemas específicos que ocurren repetidamente en entornos específicos en el desarrollo de software.

Como puede verse en la definición, el uso de patrones de diseño tiene muchas limitaciones. Asegúrese de comprender qué problema resuelve antes de usarlo. No utilice patrones de diseño a la ligera cuando no sepa qué problema resuelven.

En términos sencillos, los patrones de diseño son rutinas fijas para resolver algunos problemas en el proceso de desarrollo de software. No encapsule demasiado ni utilice patrones de diseño. Los patrones de diseño solo se utilizarán a menos que la dirección específica del cambio en los requisitos sea clara y los puntos de cambio de dirección aparezcan repetidamente; es decir, utilice los patrones de diseño con precaución.

Los patrones de diseño requieren una cierta cantidad de código de ingeniería para ser competentes. Sin embargo, es necesario comprender los patrones de diseño.

1.2 Origen del patrón de diseño

El origen de los patrones de diseño se remonta a la década de 1980, cuando fueron propuestos por primera vez por el informático Erich Gamma y otros. Definen los patrones de diseño como soluciones reutilizables a problemas y desafíos de diseño comunes.

Los patrones de diseño surgieron para resolver algunos problemas comunes en el desarrollo de software y ayudar a los desarrolladores a escribir código extensible y mantenible de manera más eficiente. Al utilizar patrones de diseño, los desarrolladores pueden aprender de éxitos anteriores y evitar reinventar la rueda mientras mejoran la legibilidad y comprensión del código.

El objetivo de los patrones de diseño es proporcionar soluciones probadas y probadas en el tiempo a problemas comunes en situaciones específicas. Un patrón de diseño no es un algoritmo o código específico, sino una plantilla para una solución en una situación específica. Se pueden aplicar en una variedad de lenguajes de programación y entornos de desarrollo.

Los patrones de diseño generalmente se dividen en tres tipos: patrones creacionales, patrones estructurales y patrones de comportamiento.

  • Los patrones de creación se centran en el mecanismo de creación de objetos;
  • Los patrones estructurales se centran en las relaciones y organización de los objetos;
  • Los patrones de comportamiento se centran en la interacción y comunicación entre objetos.

Algunos patrones de diseño comunes incluyen el patrón singleton, el patrón de fábrica, el patrón de observador, el patrón de estrategia, etc.

En una palabra, lo es: después de cumplir con los principios de diseño , se itera lentamente .

1.3 Problemas resueltos por patrones de diseño

Requisitos previos para utilizar patrones de diseño: los requisitos específicos tienen puntos tanto estables como cambiantes.

(1) Punto estable, es decir, algo que no cambiará. Si todo es estable, no hay necesidad de patrones de diseño.

(2) Puntos de cambio, es decir, cambios frecuentes. Si todos son puntos de cambio y los cambios no tienen una dirección específica, no hay necesidad de un patrón de diseño. Por ejemplo, en el desarrollo de juegos, los lenguajes de secuencias de comandos se utilizan para resolver todos los cambios, porque no es necesario volver a compilar las secuencias de comandos y se pueden actualizar en caliente.

Escenarios donde los patrones de diseño resuelven problemas específicamente: espera adaptarse a los cambios en los requisitos modificando una pequeña cantidad de código. Por ejemplo, si hay un gato activo en una habitación ordenada, ¿cómo garantizar que la habitación esté ordenada? Coloque al gato en una jaula para que pueda moverse dentro de un rango limitado.

Es decir, utilice patrones de diseño para permitir que los puntos de cambio cambien dentro de un rango limitado.

2. Conceptos básicos de los patrones de diseño.

Los patrones de diseño están relacionados con los lenguajes de desarrollo y utilizan las características del lenguaje para implementar patrones de diseño.

Para C++, las bases de los patrones de diseño son:

(1) Pensamiento orientado a objetos. Las tres características de la orientación a objetos son encapsulación (el propósito es ocultar los detalles de implementación y lograr modularidad), herencia (el propósito es lograr la expansión funcional a través de la herencia sin modificar la clase original; C ++ puede tener herencia múltiple), polimorfismo (polimorfismo estático es la sobrecarga de funciones, el mismo nombre de función pero diferentes parámetros para mostrar diferentes formas al mismo tiempo; el polimorfismo dinámico es la reescritura de funciones virtuales en herencia) . Muchas funciones de diseño dependen del polimorfismo dinámico.

(2) Principios de diseño.

2.1 Reescritura de funciones virtuales de polimorfismo de C++

Suponga una clase base con dos funciones virtuales:

clase Base{ 
	público: 
		virtual void func1(){} 
		virtual void func2(){} 
		int a; 
};

Su tabla de funciones virtuales y diseño de memoria son:

En este momento hay una subclase que hereda la Base:

Asunto de clase: Base pública { 
	público: 
		virtual void func2(){} 
		virtual void func3(){} 
		int b; 
};

Su tabla de funciones virtuales y diseño de memoria son:

Como puede ver en el diseño de la memoria, si hay una función virtual, se generará un puntero de tabla de funciones virtuales para la clase. El compilador genera automáticamente la tabla de funciones virtuales durante la compilación . La tabla de funciones virtuales es en realidad una matriz unidimensional. Las direcciones de funciones virtuales almacenadas en los elementos de la matriz se pueden llamar a las funciones correspondientes mediante compensaciones.

Para la clase Base, la tabla de funciones virtuales incluye func1 y func2; el Asunto hereda Base, y su tabla de funciones virtuales también tendrá la función virtual de Base, y la función virtual de Base en la tabla de funciones virtuales está delante de la función virtual del Asunto. .

Si el Asunto no anula la función virtual Base, entonces la dirección de la función virtual guardada en la tabla de funciones virtuales es la misma (como func1 en el ejemplo).

Si el Sujeto reescribe la función virtual Base, entonces se producirá el reemplazo en la tabla de funciones virtuales y la dirección de la función virtual correspondiente en la Base será reemplazada por la dirección de la nueva función virtual del Sujeto (como func2 en el ejemplo). ).

Si el Asunto tiene su propia función virtual nueva, también debe agregarse a la tabla de funciones virtuales.

2.2 Reflexión del polimorfismo

(1) Encuadernación anticipada. Si hay Base *p=new Asunto; si el Asunto no anula la función virtual Base, el tipo de Asunto se convertirá al tipo Base, que es de enlace anticipado.

(2) Encuadernación tardía. Si hay Base *p=new Asunto; si el Asunto reescribe la función virtual Base, entonces p en realidad apunta al objeto Asunto, que es un enlace tardío.

2.3 Método de extensión

(1) Herencia.

(2) Combinación.

2.4 Combinación polimórfica

// 
clase Asunto: base pública{ 
}; 

// 
clase Asunto{ 
privado: 
	Base base; 
};

La composición en los patrones de diseño generalmente se refiere a la composición de los punteros de clase base. La ventaja es que puede ampliar la funcionalidad de Base y desacoplar combinaciones mediante polimorfismo.

// Combinar clase base puntero 
clase Asunto{ 
privado: 
	Base *base; 
};

3. Principios de diseño

El principio de diseño es que el patrón de diseño existe antes de ser creado. Los principios de diseño son principios de desarrollo resumidos por múltiples generaciones de programadores.

3.1 Inversión de dependencia

La implementación depende de la interfaz, y la interfaz se puede convertir en una abstracción, es decir, el código de implementación específico debe depender de esta abstracción. La interfaz de uso específica (cliente) también depende de esta abstracción.

Los módulos de alto nivel no deberían depender de módulos de bajo nivel, ambos deberían depender de abstracciones;

La abstracción no debería depender de la implementación concreta, y la implementación concreta debería depender de la abstracción;

Las empresas de sistemas de conducción autónoma están en la cima y los fabricantes de automóviles están en la base. No deberían depender unos de otros. Si una parte cambia, la otra también cambiará. En lugar de eso, se debe abstraer un estándar de la industria de conducción autónoma, y ​​ambos Las personas de alto y bajo nivel dependen de él. De esta manera, están desacopladas. Los cambios entre las dos partes; los sistemas de conducción autónoma y los fabricantes de automóviles son implementaciones concretas y todos deberían confiar en los estándares de la industria de la conducción autónoma (resumen) .

3.2 Abierto y cerrado

Una clase debe estar abierta a la extensión (composición y herencia) y cerrada a la modificación . Para encapsulación y polimorfismo.

3.3 Orientado a la interfaz

El tipo de variable no se declara como una clase concreta específica, sino como una interfaz; el programa cliente no necesita conocer el tipo específico del objeto, sólo la interfaz que tiene el objeto; reduciendo las dependencias de varias partes del sistema, con lo que logrando una solución de diseño tipo "alta cohesión, acoplamiento flojo", principalmente para embalaje.

3.4 Cambios de embalaje

Separe los puntos estables y los puntos de cambio, expanda y modifique los puntos de cambio; separe los niveles de implementación de los puntos estables y los puntos de cambio. Principalmente para encapsulación y polimorfismo.

3.5 Responsabilidad única

Una clase debe tener sólo una razón para cambiar. Principalmente para embalaje.

3.6 Sustitución de Richter

El subtipo debe poder reemplazar su tipo padre; ocurre principalmente cuando la subclase anula la implementación de la clase padre, y pueden ocurrir errores en el programa original usando el tipo padre; el método de la clase padre se anula pero la responsabilidad del método de la clase padre no está implementado.

Principalmente dirigido a reescribir funciones virtuales en polimorfismo.

3.7 Aislamiento de interfaz

(1) No se debe obligar a los clientes a confiar en métodos que no utilizan;

(2) Generalmente se usa para tratar con clases que tienen muchas interfaces, y estas interfaces implican muchas responsabilidades;

(3) El cliente no debe depender de interfaces que no necesita. La dependencia de una clase de otra clase debe basarse en la interfaz más pequeña.

Aislar por calificador. Las clases dependen de interfaces y las clases están aisladas a través de interfaces.

3.8 La composición es mejor que la herencia

El acoplamiento de herencia es alto y el acoplamiento de composición es bajo.

3.9 Principio mínimo conocido

Deje que los usuarios intenten no elegir interfaces que no necesitan.

Resumir

Al introducir la definición, clasificación y escenarios de aplicación de los patrones de diseño, así como el papel de los principios de diseño, se enfatiza su importancia en el desarrollo de software. Los patrones de diseño proporcionan soluciones reutilizables para ayudar a los desarrolladores a resolver problemas comunes y desafíos de diseño y mejorar la legibilidad, comprensión y mantenibilidad del código. Los principios de diseño proporcionan orientación para los patrones de diseño, como el principio de responsabilidad única, el principio de abierto y cerrado, etc. Al aplicar patrones y principios de diseño, los desarrolladores pueden crear sistemas de software escalables, mantenibles y de alta calidad, evitar la duplicación de esfuerzos y mejorar la reutilización y flexibilidad del código.

Haga clic para seguir y conocer las nuevas tecnologías de Huawei Cloud lo antes posible ~

 

Lei Jun: La versión oficial del nuevo sistema operativo de Xiaomi, ThePaper OS, ha sido empaquetada. La ventana emergente en la página de lotería de la aplicación Gome insulta a su fundador. Ubuntu 23.10 se lanza oficialmente. ¡También podrías aprovechar el viernes para actualizar! Episodio de lanzamiento de Ubuntu 23.10: La imagen ISO fue "retirada" urgentemente debido a que contenía discurso de odio. Un estudiante de doctorado de 23 años solucionó el "error fantasma" de 22 años en Firefox. Se lanzó el escritorio remoto RustDesk 1.2.3. Wayland mejorado para soportar TiDB 7.4 Lanzamiento: Oficial Compatible con MySQL 8.0. Después de desconectar el receptor USB Logitech, el kernel de Linux falló. El maestro usó Scratch para frotar el simulador RISC-V y ejecutó con éxito el kernel de Linux. JetBrains lanzó Writerside, una herramienta para la creación de documentos técnicos.
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4526289/blog/10119766
Recomendado
Clasificación