2010-09-21 17 views
18

Soy un programador de C++, y estoy deseoso de aprender y dominar el diseño de OO.He realizado muchas búsquedas y, como todos sabemos, hay montones de material, libros, tutoriales, etc. cómo lograr un buen diseño OO. Por supuesto, entiendo que un buen diseño es algo que solo puede aportar mucha experiencia, talento individual, brillantez o, de hecho, incluso por mera suerte (¡exageración!).Secreto para lograr un buen OO Design

Pero seguro que todo comienza con un principio sólido & construyendo algunos fundamentos sólidos. ¿Puede alguien ayudarme señalando el material correcto sobre cómo comenzar esta búsqueda de aprender a diseñar directamente desde la etapa de identificación de objetos, clases etc. a la etapa de usar patrones de diseño. Habiendo dicho que soy programador pero no he tenido una experiencia en el diseño. ¿Puede ayudarme a que alguien me ayude en esta transición de programador a diseñador? Cualquier consejo, sugerencia o consejo será útil.

[Editar] Gracias por los enlaces y respuestas, necesito entrar en eso :) Como he mencionado antes, soy un programador de C++ y entiendo los conceptos básicos de OO como tales, como la herencia, la abstracción, el polimorfismo , y tener un código escrito en C++, también entiendo algunos de los patrones de diseño. Lo que no entiendo es el proceso de pensamiento básico con el que se debe abordar un requisito. Los detalles esenciales de cómo evaluar y decidir qué clases se deben tomar, y cómo definir o concluir las relaciones que deberían tener entre sí. Conocer los conceptos (en cierta medida) pero no saber cómo aplicarlos es el problema que me parece tener :(cualquier sugerencia al respecto?

+3

"Diseño OOPS" es un término extraño y divertido, sugeriría usar el mejor "diseño OO" o simplemente "OOD" en su lugar. –

+8

@Peter: Bueno, creo que la mayoría de nosotros hemos escrito un montón de código que solo puede describirse como un "diseño extraño";) – jalf

+1

@jalf, oh sí :-) Aunque no estoy seguro de que el OP signifique ese tipo de hazañas ;-) –

Respuesta

18
  1. , pero no el diseño simplista (muy) simple (diseño bastante simple, si lo prefiere): K.I.S.S.
  2. Preferir jerarquías planas, evitar jerarquías profundas.
  3. Separation of concerns es esencial.
  4. Considere otros "paradigmas" que OO cuando no parece lo suficientemente simple o elegante.
  5. De manera más general: D.R.Y. y Y.A.G.N.I ayuda a alcanzar 1.
+2

+1 para la consideración de otros paradigmas .... :) – liaK

+1

Es aún más importante en C++ donde tienes acceso nativo a otros paradigmas. En otros idiomas, a menudo es necesario agregar un idioma (C#/F #, Java/Groovy/Scala, por ejemplo) – Klaim

+1

@Klaim: C# tiene soporte nativo para muchas más funcionalidades que C++. – missingfaktor

4

como usted ha dicho, no hay nada como la experiencia. puede leer todos los libros existentes en el planeta sobre esto, usted todavía no es tan buena como si la práctica.

Comprender la teoría es bueno, pero en mi humilde opinión, no hay nada como la experiencia. Creo que la mejor manera de aprender y comprender las cosas por completo es aplicarlas en algún proyecto.

Th Si enfrenta dificultades, aprenderá a resolverlas, a veces quizás con una mala solución, pero aún así aprenderá. ¡Y si en algún momento algo te molesta y no puedes encontrar la manera de solucionarlo bien, estaremos aquí para ayudarte! :)

2

Puedo aconsejarte el libro "Head First Design Patterns" (buscar en Amazon). Es un buen punto de partida, antes de sumergirse seriamente en la biblia de la pandilla de los cuatro, y muestra los principios de diseño y los patrones más utilizados.

+0

Mi 2 centavos: a pesar de que es un buen libro para comenzar a trabajar con patrones de diseño, no es un buen punto de partida para aprender a diseñar. Será mejor que tenga una idea de cuáles son los patrones en lo que está diseñando antes de dejar que un libro decida cómo hacerlo por usted. – stefaanv

+1

en general, la primera serie no me resulta muy útil. a menudo el libro proporciona demasiadas distracciones de los mensajes y el concepto central. – poseid

+0

Gracias por la referencia al libro de Head first patterns. ¡Es un libro increíble! –

2

En pocas palabras: codifique, critique, busque una solución conocida, impleméntela y vuelva al primer paso hasta que esté (más o menos) satisfecho.

Como a menudo, la respuesta a este tipo de pregunta es: depende. Y en ese caso, depende de cómo aprendas cosas. Te diré lo que funciona para mí, porque me enfrento al problema que describes, pero no funcionará con todos y no diría que es "la respuesta perfecta".

Empiezo a codificar algo, no demasiado simple, no demasiado complejo. Luego, miro el código y pienso: está bien, ¿qué está mal? Para ello, puede utilizar los primeros tres "principios sólidos":

responsabilidad
  • Individual (? Son todas las clases que sirven a un propósito único)
  • Abrir/Cerrar principio (si desea añadir un servicio, su las clases se pueden extender con herencia, pero no es necesario alterar las funciones básicas o sus clases actuales).
  • Sustitución de Liskov (bien, este no puedo explicarlo simplemente, y le aconsejo que lea sobre él).

No intente dominarlos y comprender todo sobre ellos. Simplemente utilícelos como guía para criticar su código. Piensa principalmente en "¿y si quiero hacer esto ahora?". "¿Qué pasa si trabajo para un cliente y él quiere agregar esto o aquello?". Si su código es perfectamente adaptable a cualquier situación (que es casi imposible), es posible que haya alcanzado un diseño muy bueno.

Si no es así, considere una solución. Qué harías ? Intenta venir con una idea. Luego, lea sobre los patrones de diseño y encuentre uno que pueda responder a su problema. Vea si coincide con su idea; a menudo, es la idea que tenía, pero mejor expresada y desarrollada. Ahora, intenta implementarlo. Tomará tiempo, a menudo fallarás, es frustrante y eso es normal.

El diseño es sobre la experiencia, pero la experiencia se adquiere al criticar su propio código. Así es como comprenderá el diseño, no como algo interesante de saber, sino como la base de un código sólido. No es suficiente saber "bueno, un buen código tiene eso y eso". Es mucho mejor haber experimentado por qué, haber fallado y ver qué es lo que está mal. El problema con el patrón de diseño es que son muy abstractos. Mi método es una manera (probablemente no la única ni la mejor) de hacerlos menos abstractos para ti.

+1

Aquí hay una respuesta con el principio SOLIDO: http://stackoverflow.com/questions/845966/oop-good-class-design/845984#845984, aunque estoy de acuerdo en que SLID suena más sexy;) – stefaanv

+0

Vaya. Corregido, gracias :) – Raveline

+0

Gracias por el enlace, necesito entrar en eso :) Como mencioné antes, soy un programador de C++ y entiendo los conceptos básicos de OO como tales, como herencia, abstracción, polimorfismo y tener el código escrito en C++ también comprende algunos de los patrones de diseño. Lo que no entiendo es el proceso de pensamiento básico con el que se debe abordar un requisito. Los detalles esenciales de cómo evaluar y decidir qué clases se deben tomar, y cómo definir o concluir las relaciones que deberían tener. –

0

Los conceptos centrales en mi mente son:

  1. encapsulación - mantener la mayor cantidad de objetos ocultos de que tanto las miradas indiscretas y los dedos pegajosos del mundo exterior.
  2. Abstracción - Ocultar la mayor cantidad de los trabajos internos de que se opone a las mentes simples del código que tiene que utilizar sus objetos

Todos los demás conceptos tales como herencia, polimorfismo y el diseño de patrones son acerca de la incorporación de la dos conceptos anteriores y todavía tienen objetos que pueden resolver problemas del mundo real.

2
  1. No-solo-trabajo. Los buenos diseños rara vez son creados por una sola persona. Habla con tus colegas. Discute tu diseño con otros. Y aprender.
  2. No seas demasiado inteligente. Una jerarquía compleja con 10 niveles de herencia rara vez es un buen diseño. Asegúrese de que pueda explicar claramente cómo funciona su diseño. Si no puede explicar los principios básicos en 5 minutos, su diseño probablemente sea demasiado complejo.
  3. Aprende trucos de los maestros: Alexandrescu, Meyers, Sutter, GoF.
  4. Prefieren la extensibilidad sobre la perfección. El código fuente escrito hoy será insuficiente en 3 años. Si escribe su código para que sea perfecto ahora, pero inextensible, tendrá un problema más adelante. Si escribe su código para que sea extensible (pero no perfecto), aún podrá adaptarlo más tarde.
12

No hay ningún secreto. Es sudor, no magia.

No se trata de hacer una cosa bien. Está equilibrando muchas cosas que no deben salir mal. A veces, trabajan en sincronía, a veces, trabajan uno contra el otro. El diseño es solo un grupo de estos aspectos. El mejor diseño no ayuda si el proyecto falla (por ejemplo, porque nunca se envía).

La primera regla que había puesto adelante es:

1. No hay absolutos sigue directamente de las "muchas cosas para equilibrar SECO, etc., están YAGNI directrices, siguiendo estrictamente ellos. no puede garantizar el buen diseño, si es seguido por la letra que pueden hacer que su proyecto falle

Ejemplo:. SECO Uno de los principios más fundamentales, sin embargo, los estudios muestran que la complejidad de los bacalaos pequeños Los fragmentos de código aumentan en un factor de 3 o más cuando se aíslan, debido a la verificación de las condiciones previas y posteriores, el manejo de errores y la generalización a varios casos relacionados. Entonces el principio necesita ser debilitado a "D.R.Y. (al menos, no demasiado)" - cuándo y cuándo no es la parte difícil.

La segunda regla no es muy común:

2. Una interfaz debe ser más simple que la implementación

suena trivial para ser pegadizo. Sin embargo, hay mucho que decir al respecto:

La premisa de OO era administrar los tamaños de programas que ya no se podían administrar con programación estructurada. El mecanismo principal es encapsular la complejidad: podemos ocultar la complejidad detrás de una interfaz más simple y luego olvidarnos de esa complejidad.

La complejidad de la interfaz implica la documentación, las especificaciones de manejo de errores, las garantías de rendimiento (o su ausencia), etc. Esto significa que, p. reducir la declaración de interfaz mediante la introducción de casos especiales no es una reducción de la complejidad, simplemente una confusión.

3-N Aquí es donde pongo la mayoría de las otras menciones, que ya se han explicado muy bien.

Separación de preocupaciones, K.I.S.S, SOLID principio, D.R.Y., aproximadamente en ese orden.


¿Cómo crear software de acuerdo con estas directrices?

Las pautas anteriores ayudan a evaluar un trozo de código. Desafortunadamente, no hay una receta para llegar allí. "Experimentado" significa que tiene una buena idea de cómo estructurar su software, y algunas decisiones simplemente se sienten mal. Tal vez todos los principios son solo racionalizaciones después del hecho.

La ruta general es dividir un sistema en responsabilidades, hasta que las piezas individuales sean manejables.

Existen procesos formales para eso, pero estos solo funcionan alrededor del hecho de que lo que hace que un componente bueno y aislado sea una decisión subjetiva. Pero al final, para eso nos pagan.

Si tiene una idea aproximada de todo el sistema, no es incorrecto comenzar con una de estas piezas como semilla, y hacerlas crecer en un "núcleo". Top-down y bottom-up no son antípodas.

Practica, practica, practica. Crea un programa pequeño, hazlo funcionar, cambia los requisitos y haz que se ejecute nuevamente. La parte de "requisitos cambiantes" no necesita entrenar mucho, tenemos clientes para eso.

Revisiones posteriores al proyecto - trate de acostumbrarse a ellas, incluso para sus proyectos personales. Después de que está sellado, listo, evalúa qué estuvo bien, qué fue malo. Considere que el código fuente fue descartado, es decir, ¿no considera que sessison es "lo que debería arreglarse"?

Conway's Law dice que "Un sistema refleja la estructura de la organización que lo construyó". Eso se aplica al software más complejo que he visto, y los estudios formales parecen confirmarlo. Podemos derivar algunos bits de información de eso:

  • Si la estructura es importante, también lo son las personas con las que trabaja.
  • O tal vez la estructura no es tan importante. No hay una estructura de derecha (justo muchos los incorrectos para evitar)
4

Voy a citar a Marcus Baker hablando acerca de cómo lograr un buen diseño orientado a objetos en un mensaje en el foro aquí: http://www.sitepoint.com/forums/showpost.php?p=4671598&postcount=24

1) Tome un hilo de un caso de uso.

2) Implementarlo como antes.

3) Toma otro hilo.

4) Implementarlo como antes.

5) Busque las características comunes.

6) Factorice el código para que las características se recopilen en las funciones. Objetivo para la claridad del código. Sin globales, pasa todo.

7) Cualquier bloque de código que no esté claro, agrupe en una función también.

8) Implemente otro hilo de cualquier forma antigua, pero use sus funciones existentes si son instantáneas.

9) Una vez que esté funcionando, vuelva a factorizar para eliminar la duplicación. A estas alturas, puede descubrir que está pasando pedazos de cosas similares de una función a otra. Para eliminar la duplicación, muévala a objetos.

10) Implemente otro hilo una vez que su código sea perfecto.

11) Refactor para evitar la duplicación hasta que se aburra.

Ahora el bit OO ...

12) En este momento deberían estar surgiendo algunos roles más altos para los candidatos. Agrupe esas funciones en roles por clase.

13) Vuelva a configurar de nuevo con el objetivo de la claridad. Ninguna clase más grande que un par de páginas de código, ningún método de más de 5 líneas. Sin herencia a menos que la variación sea solo unas pocas líneas de código.

partir de este momento se puede completar un ciclo para un poco ...

14) Implementar un hilo de casos de uso de cualquier manera.

15) Refactor como el anterior. La refactorización incluye el cambio de nombre de objetos y clases a medida que evolucionan sus significados.

16) Repita hasta que se aburra.

Ahora las cosas de patrones!

Una vez que tenga un par de docenas de clases y un poco de funcionalidad en funcionamiento, puede observar que algunas clases tienen un código muy similar, pero no hay una división obvia (no, no use herencia). En este punto, consulte los libros de patrones para conocer las opciones para eliminar la duplicación. Sugerencia: probablemente quieras "Estrategia".

Los siguientes repeticiones ...

17) Implementar otro hilo de un caso de uso de cualquier manera.

18) Refactorizar métodos de hasta cinco líneas o menos, clases de hasta 2 páginas o menos (preferiblemente mucho menos), busque patrones para eliminar la duplicación de nivel superior si realmente hace que el código sea más limpio.

19) Repita hasta que sus constructores de nivel superior tengan muchos parámetros, o se encuentre usando "nuevo" mucho para crear objetos dentro de otros objetos (esto es malo).

Ahora tenemos que limpiar las dependencias. Cualquier clase que funcione no debe usar "nuevo" para crear cosas dentro de sí misma. Pasa esos sub objetos desde afuera. Las clases que no realizan trabajos mecánicos pueden usar el operador "nuevo". Simplemente ensamblan cosas, las llamaremos fábricas. Una fábrica es un papel en sí mismo. Una clase debe tener un solo rol, por lo tanto, las fábricas deben ser clases separadas.

20) Factorizar las fábricas.

Ahora repetimos de nuevo ...

21) Implementar otro hilo de un caso de uso de cualquier manera.

22) Refactorizar métodos de hasta cinco líneas o menos, clases de hasta 2 páginas o menos (preferiblemente mucho menos), busque patrones para eliminar la duplicación de nivel superior si realmente hace que el código sea más limpio, asegúrese de usar un separador clases para fábricas.

23) Repita hasta que sus clases de nivel superior tengan un número excesivo de parámetros (digamos 8+).

Probablemente ya haya terminado. De lo contrario, busque el patrón de inyección de dependencia ...

24) Cree (solo) sus clases de nivel superior con un inyector de dependencia.

Entonces puede repetir de nuevo ...

25) Implementar otro hilo de un caso de uso de cualquier forma anterior.

26) Refactorizar métodos de hasta cinco líneas o menos, clases de hasta 2 páginas o menos (preferiblemente mucho menos), buscar patrones para eliminar la duplicación de nivel superior si realmente hace que el código sea más limpio, asegúrese de usar un dispositivo por separado clases para fábricas, pasan las dependencias de nivel superior (incluidas las fábricas) a través de DI.

27) Repita.

En cualquier etapa de esta heurística es probable que desee echar un vistazo a desarrollo impulsado por prueba. Por lo menos, detendrá las regresiones mientras se refactoriza.

Obviamente, este es un proceso bastante simple, y la información contenida en el mismo no se debe aplicar a cada situación, pero me siento como Marcus lo hace bien, especialmente con respecto al proceso se debe utilizar para diseñar OO código. Después de un tiempo, comenzarás a hacerlo de forma natural, se convertirá en una segunda naturaleza. Pero mientras aprenden a hacerlo, este es un gran conjunto de pasos a seguir.

Cuestiones relacionadas