2009-11-23 20 views
6

Entonces hay muchas maneras de estructurar objetos (estoy hablando de OOP aquí). Para la pregunta, usaré el ejemplo clásico de "Coche" de OOP. Básicamente, ¿cómo sé cuándo convertir el automóvil en un objeto, o la rueda de un automóvil en un objeto, cuando ambas estructuras del programa lograrán el objetivo?¿Cómo diseñar objetos?

¿Cómo clasifico y categorizo ​​las partes de un objeto para determinar si son más adecuadas como atributos simples o variables de un objeto, o si realmente necesitan ser un objeto?

Respuesta

6

Bueno, lo primero que tiene darse cuenta es que OOAD ("análisis y diseño orientado a objetos") es una herramienta y no un medio para un fin. Lo que obtienes de ese proceso es un modelo, no una verdadera representación de lo que estás modelando. Ese modelo hace ciertas suposiciones. El propósito de ese modelo es resolver un problema que tienes.

Entonces, ¿cómo sabes cómo diseñar objetos? ¿Cómo sabes si lo has hecho bien? Por el resultado final: ¿ha resuelto tu problema?

Por lo tanto, para el ejemplo de automóvil, en algunos modelos el número de vehículos podría ser simplemente un número entero, por ejemplo, el tráfico de automóviles a través de una intersección en un modelo de tráfico. En un modelo así, rara vez le importa la marca, el modelo o la construcción de los automóviles, solo el número. Puede que le importe el tipo de vehículo hasta el punto de que sea un camión o un automóvil (por ejemplo). ¿Lo modela como un objeto de vehículo con un tipo de automóvil o camión? ¿O solo separa los recuentos de carCount y truckCount?

La respuesta corta es: lo que funcione mejor.

La prueba normal de que algo sea un objeto o no es ¿tiene un comportamiento? Recuerde que en última instancia, objetos = datos + comportamiento.

lo que podríamos decir que los coches tienen el siguiente estado:

  • de ruedas;

  • Altura de la suspensión;
  • Unidad izquierda o derecha;
  • Color;
  • Ancho;
  • Peso;
  • Longitud;
  • Altura;
  • de puertas;

  • Si tiene un quemacocos;
  • Si tiene un estéreo, reproductor de CD, reproductor de MP3 y/o satélite;
  • Tamaño del tanque de gasolina;
  • Número de cilindros;
  • de las cargas de turbo y/o inyección de combustible;

  • Par máximo;
  • Potencia de freno máxima;
  • y así sucesivamente.

Lo más probable es que solo se preocupe por un pequeño subconjunto de eso: elija lo que sea relevante. Un juego de carreras podría entrar en más detalles sobre las ruedas, como qué tan calientes están, qué tan gastadas, el ancho y el tipo de banda de rodadura, etc. En tal caso, se podría decir que un objeto Wheel es una colección de todo ese estado (pero poco comportamiento) porque un automóvil tiene un número de ruedas y las ruedas son intercambiables.

De modo que aparece el segundo punto sobre los objetos: un objeto puede existir debido a una relación tal que el objeto representa un conjunto completo de datos. Entonces una Rueda podría tener banda de rodadura, ancho, temperatura, etc. No puedes dividir eso y decir que un auto tiene banda de rodadura pero no ancho de rueda, por lo que tiene sentido que Wheel sea un objeto, ya que una rueda en su totalidad es intercambiable.

Pero, de nuevo, ¿tiene sentido para qué está haciendo? Esa es la pregunta clave.

+1

+1 Muy buena respuesta :) –

5

No comience clasificando cosas - parece que las personas están demasiado ansiosas por comenzar a construir jerarquías de herencia.

escriba una lista de escenarios concretos y concretos - lo que su aplicación hará, paso a paso. Un modelo de objetos solo es útil si hace lo que necesita: empiece a trabajar desde los escenarios para ver qué objetos y comportamientos comunes puede eliminar de cada uno.

identifique los "roles" en sus escenarios - nombres de clases no necesariamente reales - solo vagos "roles" que aparecen cuando se piensa en escenarios concretos de cómo funcionará su software. Estos roles pueden convertirse más adelante en clases, interfaces, clases abstractas, lo que sea que necesites, al principio solo son marcadores de posición para realizar un tipo de trabajo.

Haz lo que cada función "hace". La clave es tener un montón de roles con nombre: eso identifica las cosas que los objetos harán. Thins se trata de destilar un conjunto de cosas que cada función puede hacer: pueden hacer todo, o juntar un montón de otros objetos para hacer el trabajo, o pueden coordinar el trabajo ... depende de tus escenarios .

Lo más importante en OOD/OOP - es OBJETOS DO THINGS - no lo que hay dentro de ellos - lo que hacen.

No piense en la herencia desde el principio - porque le atará en jerarquías sobrecomplicadas y le hará pensar en términos de programación orientada a SQL en lugar de programación orientada a objetos. La herencia es solo una forma de compartir un código común. Hay un montón de otras maneras - delegación, mixins, programación basada en prototipos ...

Aquí hay algunas pautas que se me ocurrió a ayudar con esto:

What should be on a checklist that would help someone develop good OO software?

0

Los atributos o variables son a menudo tipos "básicos" de un idioma. La pregunta es qué puedes abstraer sensiblemente.

Por ejemplo, se puede reducir un Wheel a los descriptores compuestos de tipos base como números enteros, valores de coma flotante y cadenas, que representan atributos característicos de cualquiera de las ruedas: numberOfTreads, diameter, width, recommendedPressure, brand. Esos atributos se pueden expresar con tipos base para hacer un objeto Wheel.

¿Puede agrupar algunos de esos atributos en una disposición más abstracta que puede reutilizar, independientemente de Wheel? Creo que si.Tal vez crear un objeto Dimensions con los atributos diameter y width. Entonces su Wheel tiene una instancia de objeto Dimensions asociada, en lugar de diameter y width. Pero podría pensar en usar ese objeto Dimensions con otros objetos, que pueden no ser necesariamente instancias Wheel.

Subiendo en la lista, puede reducir un Car que se compone de tipos de base, sino también de otros objetos, como objetos Wheel. Es sensato hacerlo, ya que otros vehículos motorizados y no motorizados (como un Bicycle) también contienen Wheel instancias.

Resumiendo Wheel y Dimensions le permite reutilizar estos tipos de objetos en diferentes contextos que inicialmente no considere. Hace su vida un poco más fácil porque tiene menos código para reescribir, en teoría.

Si puede crear una jerarquía de objetos, hasta el punto en que el objeto más profundo y de nivel más bajo solo está formado por unos pocos tipos de base, probablemente sea un buen lugar para comenzar.

0

Si bien es cierto que "ambas estructuras de programa cumplirían la meta" igualmente bien, entonces no importa cuál elija.

Si, sin embargo, el programa no tiene un único "objetivo" fijo pero evolucionará significativamente a lo largo de su vida útil, elija uno por ahora y refactorícese según sea necesario como lo dicten las futuras modificaciones. Lo llamamos "software" por una razón.

1

Me gusta Wirfs-Brock's Responsibility-Driven Design (RDD) y también recomiendo este enfoque actualizado (documento gratuito) Responsibility-Driven Modeling de Alistair Cockburn.

En más de 15 años de desarrollo de OO, cada vez que siento que me pierdo en una arquitectura de software, volver a los conceptos básicos de RDD siempre me ayuda a aclarar qué se supone que debe hacer el software y cómo.

Si le gusta un enfoque basado en pruebas, this article muestra cómo relacionar el RDD con burlarse de objetos y pruebas.

+0

¡Yay! Yo también. El RDD es lo que más diferencia a los proyectos en los que he trabajado. (De acuerdo, admitido, todos son proyectos impulsados ​​por pruebas, pero RDD tiene tanto potencial para la reducción de la complejidad y para eliminar el pensamiento del programador Pascal en languganes de OOP). – daf

2

Aquí hay algunas buenas respuestas, pero posiblemente más de las que estaba buscando. Para hacer frente a sus preguntas específicas brevemente:

  • ¿Cómo puedo saber cuándo hacer el coche un objeto, o al volante de un coche de un objeto, cuando ambas estructuras de programas cumplirían el objetivo?

    Cuando necesita distinguir una instancia de otra, necesita un objeto. La distinción clave de un objeto es: tiene identidad.

    Extendiendo esta respuesta ligeramente a las clases, cuando los comportamientos y/o propiedades de dos objetos similares divergen, necesita una nueva clase.

    Por lo tanto, si está modelando una simulación de tráfico que cuente las ruedas, una clase de vehículo con una propiedad NumberOfWheels puede ser suficiente. Si está modelando una simulación de carreras con una física detallada de la superficie de la carretera y el torque de la rueda, cada rueda probablemente necesite ser un objeto independiente.

  • ¿Cómo clasifico y clasifico las partes de un objeto para determinar si son más adecuadas como atributos simples o variables de un objeto, o si realmente necesitan ser un objeto ellos mismos?

    Las distinciones clave son la identidad y el comportamiento. Una parte con existencia única es un objeto. Una parte con comportamiento autónomo requiere su propia clase.

    Por ejemplo, si está creando una simulación de choque de automóvil muy simple, NumberOfPassengers y DamageResistance pueden ser suficientes propiedades de una clase genérica de vehículo. Esto sería suficiente para decirle si el automóvil se sumó y los pasajeros sobrevivieron. Si su simulación es mucho más detallada, quizás desee saber qué tan lejos fue arrojado cada pasajero en una colisión frontal, entonces necesitaría una clase de Pasajero y distintos objetos de Pasajero en cada Vehículo.

0

Grow sus clases de abajo hacia arriba.

1) Los límites de clase y la semántica dependen del contexto. Hasta que tengas un contexto, no tienes nada. (Puede que ni siquiera tenga un automóvil en su ejemplo). El contexto viene dado por la historia del usuario (o caso de uso).

2) Bote todo el estado y el comportamiento sugerido por el contexto dado en una clase (puede nombrar esto después de la historia del usuario si lo desea).

3) Use sistemáticamente Refactoring para extraer esta clase en clases separadas. Mientras refactoriza, use las clases existentes como oportunidades de reutilización.

Cuando haya terminado, tendrá un conjunto de clases bien definidas que son suficientes para satisfacer las necesidades de la historia de usuario dada (y las historias de los usuarios anteriores).

Cuestiones relacionadas