tutorial oriented language help documentacion development concepts c# oop

c# - oriented - ¿Qué debería estar en una lista de verificación que ayude a alguien a desarrollar un buen software de OO?



object oriented concepts c# (12)

Algunas de las reglas son agnósticas del lenguaje, algunas de las reglas difieren de un idioma a otro.

Aquí hay algunas reglas y comentarios que contradicen algunas otras reglas publicadas anteriormente:

  • OO tiene 4 principios: abstracción, encapsulación, polimorfismo y herencia.
    Lee sobre ellos y tenlos en cuenta.

  • Modelado: se supone que sus clases modelan entidades en el dominio del problema:
    Divide el problema en subdominios (paquetes / espacios de nombres / ensamblajes)
    luego divida las entidades en cada subdominio a clases.
    Las clases deben contener métodos que modelen lo que hacen los objetos de ese tipo.

  • Use UML, piense en los requisitos, casos de uso, luego diagramas de clase, secuencias. (aplicable principalmente para diseño de alto nivel - principales clases y procesos).

  • Patrones de diseño: buen concepto para cualquier idioma, la implementación difiere entre idiomas.

  • Struct vs. class: en C # se trata de pasar datos por valor o por referencia.

  • Interfaz vs. clase base, es una clase base, hace una interfaz.

  • TDD: esto no es OO, de hecho, puede causar una falta de diseño y llevar a muchas reescrituras. (Scrum, por ejemplo, recomienda no hacerlo, para XP es un deber).

  • La Reflexión de C # de alguna manera anula la OO (por ejemplo, la serialización basada en la reflexión), pero es necesario para los marcos avanzados.

  • Asegúrese de que las clases no "conozcan" otras clases a menos que tengan que hacerlo, dividir en varios ensamblajes y ser escaso con las referencias ayuda.

  • AOP (Aspect Oriented Programming) mejora la programación orientada a objetos (ver PostSharp, por ejemplo) de una manera tan revolucionaria que al menos deberías buscarla y ver su clip.

  • Para C #, lea las pautas de MS (consulte las pautas en el índice de ayuda de MSDN de VS), tienen muchas pautas y convenciones útiles allí

  • Libros recomendados:
    Directrices de diseño de marco: convenciones, expresiones idiomáticas y patrones para bibliotecas .NET reutilizables
    C # 3.0 en pocas palabras

He usado lenguajes y técnicas de programación OO hace años (principalmente en C ++) pero en el tiempo intermedio no he hecho mucho con OO.

Estoy empezando a hacer una pequeña utilidad en C #. Simplemente podría programarlo todo sin utilizar una buena práctica de OO, pero sería un buen repaso para que aplique técnicas de OO.

Al igual que los niveles de normalización de la base de datos, estoy buscando una lista de verificación que me recuerde las diversas reglas básicas para un "buen" programa orientado a objetos: una lista concisa de sí / no que puedo leer de vez en cuando durante el diseño y la implementación para evitarlo. De pensar y trabajar procedimentalmente. Sería aún más útil si contuviera los términos y conceptos de OO adecuados para que cualquier elemento de verificación pueda buscarse fácilmente para obtener más información.

¿Qué debería estar en una lista de verificación que ayude a alguien a desarrollar un buen software de OO?

A la inversa, ¿qué ''pruebas'' podrían aplicarse para mostrar que el software no es OO?


Asegúrese de leer y entender lo siguiente

  • Encapsulacion
    • (Asegurándose de que solo exponga el estado y la funcionalidad mínimos para realizar el trabajo)
  • Polimorfismo
    • (Habilidad para que los objetos derivados se comporten como sus padres)
  • La diferencia entre una interfaz y una clase abstracta.
    • (Una clase abstracta permite que la funcionalidad y el estado se compartan con sus descendientes, una interfaz es solo la promesa de que la funcionalidad se implementará)


Me gusta this lista, aunque podría ser un poco densa para ser utilizada como una lista de verificación.


Parece que quieres algunas preguntas básicas de sí / no para hacerte a lo largo del camino. Todos han dado algunas listas geniales de "haz esto" y "piensa así", así que aquí está mi grieta en algunos simples sí / no.

¿Puedo responder sí a todo esto?

  • ¿Mis clases representan los sustantivos que me interesan?
  • ¿Mis clases proporcionan métodos para acciones / verbos que puede realizar?

¿Puedo responder no a todo esto?

  • ¿Tengo datos de estado globales que podrían ser colocados en un singleton o almacenados en implementaciones de clase que funcionen con él?
  • ¿Puedo eliminar cualquier método público en una clase y agregarlos a una interfaz o hacerlos privados / protegidos para encapsular mejor el comportamiento?
  • ¿Debo usar una interfaz para separar un comportamiento de otras interfaces o la clase de implementación?
  • ¿Tengo el código que se repite entre clases relacionadas que puedo mover a una clase base para una mejor reutilización y abstracción del código?
  • ¿Estoy probando el tipo de algo para decidir qué acción hacer? Si es así, ¿se puede incluir este comportamiento en el tipo de base o la interfaz que el código en cuestión está utilizando para permitir un uso más efectivo de la abstracción o debería ser refactorizado el código en cuestión para usar una mejor clase base o interfaz?
  • ¿Estoy revisando repetidamente algunos datos de contexto para decidir qué tipo crear? Si es así, ¿se puede abstraer esto en un patrón de diseño de fábrica para una mejor abstracción de la lógica y la reutilización del código?
  • ¿Es una clase muy grande con múltiples enfoques de funcionalidad? Si es así, ¿puedo dividirlo en varias clases, cada una con su único propósito?
  • ¿Tengo clases no relacionadas que heredan de la misma clase base? Si es así, ¿puedo dividir la clase base en mejores abstracciones o puedo usar la composición para obtener acceso a la funcionalidad?
  • ¿Mi jerarquía de herencia se ha vuelto terriblemente profunda? Si es así, ¿puedo aplanarlo o separar cosas a través de interfaces o la funcionalidad de división?
  • ¿Me he preocupado demasiado por mi jerarquía de herencia?
  • Cuando le explico el diseño a un patito de goma, ¿me siento estúpido por el diseño o estúpido por hablar con un pato?

Sólo algunos rápidos de la parte superior de mi cabeza. Espero que ayude, OOP puede volverse bastante loco. No incluí ningún sí / no para cosas más avanzadas que generalmente son una preocupación con aplicaciones más grandes, como la inyección de dependencia o si debería dividir algo en diferentes conjuntos de lógica / servicio / lógicas ... por supuesto, espero que al menos separar su interfaz de usuario de su lógica.


Recopilado de varios libros, programadores famosos de C # y consejos generales (no mucho si algo de esto es mío; es en el sentido de que estas son varias preguntas que me pregunto durante el desarrollo, pero eso es todo):

  • ¿Estructuras o clases? Si el elemento que está creando es un valor propio, conviértalo en una estructura. Si es un "objeto" con atributos y subvalores, métodos y posiblemente un estado, conviértalo en un objeto.
  • Clases selladas : si va a crear una clase y no necesita explícitamente poder heredarla, sellarla. (Lo hago por la supuesta ganancia de rendimiento)
  • No se repita : si se encuentra copiando el código (a / e), probablemente debería ( pero no siempre ) repensar su diseño para minimizar la duplicación de código.
  • Si no necesita proporcionar una implementación básica para una clase abstracta dada, conviértala en una interfaz.
  • El principio de especialización : cada objeto que tengas debe hacer solo una cosa. Esto ayuda a evitar el "objeto de Dios".
  • Use las propiedades para el acceso público : esto se ha debatido una y otra vez, pero es realmente lo mejor que se puede hacer. Las propiedades le permiten hacer cosas que normalmente no puede hacer con los campos, y también le permite un mayor control sobre cómo se obtiene y establece el objeto.
  • Singletons : otro tema controvertido, y aquí está la idea: solo úselos cuando lo necesite absolutamente. La mayoría de las veces, un grupo de métodos estáticos puede servir para un singleton. (Aunque si absolutamente necesitas un patrón de singleton, usa el excelente de Jon Skeet )
  • Acoplamiento suelto : asegúrate de que tus clases dependan las unas de las otras lo menos posible; asegúrese de que sea fácil para los usuarios de su biblioteca intercambiar partes de su biblioteca con otras (o partes personalizadas). Esto incluye el uso de interfaces cuando sea necesario, la encapsulación (otros lo han mencionado) y la mayoría del resto de los principios en esta respuesta.
  • Diseñe teniendo en cuenta la simplicidad : a diferencia del pastel de pastel, es más fácil diseñar algo simple ahora y agregar más tarde de lo que es diseñar complejo ahora y eliminar más tarde.

Podría tirar algo o todo esto por la puerta si soy:

  • Escribiendo un proyecto personal
  • realmente apurado por hacer algo (pero volveré a hacerlo más tarde ... en algún momento .....;))

¡Estos principios ayudan a guiar mi codificación diaria y han mejorado enormemente la calidad de mi codificación en algunas áreas! ¡Espero que ayude!


UML - Unified Modeling Language, para modelar objetos y definir la estructura y las relaciones entre clases.

http://en.wikipedia.org/wiki/Unified_Modeling_Language

Luego, por supuesto, las técnicas de programación para OO (la mayoría ya mencionada)

  • Ocultación de información
  • Abstracción
  • Interfaces
  • Encapsulacion
  • Herencia / polimorfismo

Una de las mejores fuentes sería el libro "Refactoring" de Martin Fowler, que contiene una lista (y detalles de apoyo) de olores de código orientados a objetos que tal vez quiera considerar refactoring.

También recomendaría las listas de verificación en el "Código limpio" de Robert Martin.


  • SÓLIDO
  • SECO
  • TDD
  • Composición sobre herencia

  • Los datos pertenecen al código que opera en ellos (es decir, en la misma clase). Esto mejora la capacidad de mantenimiento debido a que muchos campos y métodos pueden ser privados ( encapsulación ) y, por lo tanto, se eliminan de la consideración al observar la interacción entre los componentes.
  • Use el polimorfismo en lugar de las condiciones : siempre que tenga que hacer cosas diferentes según la clase que sea un objeto, intente poner ese comportamiento en un método que las diferentes clases implementan de manera diferente, de modo que todo lo que tiene que hacer es llamar a ese método
  • Use la herencia con moderación, prefiera la composición : la herencia es una característica distintiva de la programación de OO y, a menudo, se la ve como la "esencia" de la POO. De hecho, está gravemente sobreutilizada y debe clasificarse como la característica menos importante.

  • Los objetos hacen cosas. (¡El punto más importante de todo OOP!) No piense en ellos como "titulares de datos": envíeles un mensaje para hacer algo. ¿Qué verbos debería tener mi clase? La escuela de pensamiento "Diseño impulsado por responsabilidad" es brillante para esto. (Ver Diseño de objetos: roles, responsabilidades y colaboraciones , Rebecca Wirfs-Brock y Alan McKean, Addison-Wesley 2003, ISBN 0201379430).
  • Para cada cosa que el sistema debe hacer, idear un montón de escenarios concretos que describan cómo los objetos se comunican entre sí para realizar el trabajo . Esto significa pensar en términos de diagramas de interacción y representar las llamadas a métodos. - No empieces con un diagrama de clase: eso es pensar en SQL, no pensar en OO.
  • Aprender el desarrollo guiado por pruebas. Nadie obtiene su modelo de objeto por adelantado, pero si hace TDD, está preparando el terreno para asegurarse de que su modelo de objeto hace lo que necesita y es seguro refactorizar cuando las cosas cambian más adelante.
  • Solo compile para los requisitos que tienes ahora , no te obsesiones con la "reutilización" o cosas que serán "útiles más adelante". Si solo construye lo que necesita en este momento, mantendrá mucho más abierto el espacio de diseño de las cosas que podría hacer posteriormente.
  • Olvídate de la herencia cuando estás modelando objetos. Es solo una forma de implementar código común. Cuando está modelando objetos, simplemente simule que está mirando cada objeto a través de una interfaz que describe lo que se le puede pedir que haga.
  • Si un método toma muchos parámetros o si necesita llamar repetidamente a un grupo de objetos para obtener gran cantidad de datos, el método podría estar en la clase incorrecta. El mejor lugar para un método es justo al lado de la mayoría de los campos que usa en la misma clase (o superclase ...)
  • Lee un libro de patrones de diseño para tu idioma. Si es C #, pruebe "Design Patterns in C #" de Steve Metsker. Esto le enseñará una serie de trucos que puede usar para dividir el trabajo entre objetos.
  • No pruebe un objeto para ver de qué tipo es y luego actúe de acuerdo con ese tipo : es un olor de código que el objeto probablemente debería estar haciendo el trabajo. Es un indicio de que debe llamar al objeto y pedirle que haga el trabajo. (Si solo algunos tipos de objetos hacen el trabajo, simplemente puede tener implementaciones de "no hacer nada" en algunos objetos ... Eso es OOP legítimo).
  • Poner los métodos y los datos en las clases correctas hace que el código OO se ejecute más rápido (y le da a las máquinas virtuales la oportunidad de optimizar mejor), no solo es estético o teórico. El estudio de Sharble y Cohen lo señala: consulte http://portal.acm.org/citation.cfm?doid=159420.155839 (consulte la gráfica de métricas sobre "número de instrucciones ejecutadas por escenario")

  • ¿He definido claramente los requisitos? La documentación de requisitos formales puede no ser necesaria, pero debe tener una visión clara antes de comenzar la codificación. Las herramientas de mapeo mental y los prototipos o bocetos de diseño pueden ser buenas alternativas si no necesita documentación formal. Trabaje con los usuarios finales y las partes interesadas lo antes posible en el proceso del software, para asegurarse de que está implementando lo que necesitan.

  • ¿Estoy reinventando la rueda? Si está codificando para resolver un problema común, busque una biblioteca robusta que ya resuelva este problema. Si cree que ya puede haber resuelto el problema en otra parte de su código (o que un compañero de trabajo lo haya hecho), busque primero una solución existente.

  • ¿Mi objeto tiene un propósito claro y único? Siguiendo el principio de la encapsulación, un objeto debe tener un comportamiento junto con los datos con los que opera. Un objeto solo debe tener una gran responsabilidad.

  • ¿Puedo codificar a una interfaz? El diseño por contrato es una excelente manera de habilitar las pruebas unitarias, documentar los requisitos detallados a nivel de clase y fomentar la reutilización del código.

  • ¿Puedo poner mi código a prueba? El desarrollo dirigido por pruebas (TDD) no siempre es fácil; pero las pruebas unitarias son invaluables para refactorizar y verificar el comportamiento de regresión después de hacer cambios. Va de la mano con Design By Contract.

  • ¿Estoy sobre diseño? No intente codificar un componente reutilizable. No intente anticipar los requisitos futuros. Estas cosas pueden parecer contradictorias, pero conducen a un mejor diseño. La primera vez que codifiques algo, solo implícalo de la manera más directa posible y haz que funcione. La segunda vez que uses la misma lógica, copia y pega. Una vez que tenga dos secciones de código de trabajo con lógica común, puede refactorizar fácilmente sin intentar anticipar requisitos futuros.

  • ¿Estoy introduciendo código redudante? Don''t Repeat Yourself (DRY) es el principal impulsor de la refactorización. Utilice copiar y pegar solo como primer paso para refactorizar. No codifiques lo mismo en diferentes lugares, es una pesadilla de mantenimiento.

  • ¿Es este un patrón de diseño común, anti-patrón, o olor de código? Familiarícese con las soluciones comunes a los problemas de diseño de OO y búsquelos a medida que codifica, pero no intente forzar un problema para que se ajuste a un patrón determinado. Tenga cuidado con el código que cae en un patrón común de "mala práctica".

  • ¿Mi código está demasiado unido? El acoplamiento suelto es un principio que intenta reducir las interdependencias entre dos o más clases. Algunas dependencias son necesarias; pero cuanto más dependa de otra clase, más tendrá que corregir cuando esa clase cambie. No permita que el código en una clase dependa de los detalles de implementación de otra clase; use un objeto solo de acuerdo con su contrato.

  • ¿Estoy exponiendo demasiada información? Practicar la ocultación de la información. Si un método o campo no necesita ser público, hágalo privado. Exponga solo la API mínima necesaria para que un objeto cumpla su contrato. No haga que los detalles de la implementación sean accesibles a los objetos del cliente.

  • ¿Estoy codificando a la defensiva? Compruebe las condiciones de error, y Fallo rápido. No tenga miedo de usar excepciones, y deje que se propaguen. En el caso de que su programa alcance un estado inesperado, es mucho mejor abortar una operación, registrar un seguimiento de la pila para que trabaje y evitar comportamientos impredecibles en su código de flujo descendente. Siga las mejores prácticas para limpiar recursos, como la instrucción using() {} .

  • ¿Podré leer este código en seis meses? Buen código es legible con documentación mínima. Pon comentarios cuando sea necesario; pero también escriba código que sea intuitivo y use nombres significativos de clases, métodos y variables. Practica el buen estilo de codificación; Si está trabajando en un proyecto de equipo, cada miembro del equipo debe escribir un código que se vea igual.

  • ¿Todavía funciona? Prueba temprano, prueba a menudo. Después de introducir una nueva funcionalidad, regrese y toque cualquier comportamiento existente que pueda haber sido afectado. Haga que otros miembros del equipo revisen y prueben su código. Vuelva a ejecutar las pruebas de unidad después de realizar cambios y manténgalas actualizadas.