2010-09-10 11 views
9

¿Dónde dibuja la línea cuando mueve funciones que operan en datos en la clase que contiene esos datos? Por ejemplo, imagine que tiene una clase simple que almacena una descripción del clima, con variables de temperatura, humedad, velocidad y dirección del viento, y la hora en que se tomó la medición. Ahora imagine que tiene un objeto de esta clase y desea transmitirlo a otra persona: otro proceso, otra máquina, lo que sea. ¿Pones el código para transmitir el objeto en el objeto mismo, por ejemplo, al agregar un método de Enviar (tipo de destino) a la clase de datos simple? ¿O mantiene este tipo de características en clases separadas que pueden enviar y recibir cualquier cosa por el medio, ya sea de redes, archivos de E/S, comunicaciones entre procesos, o algo similar?Objetos que se envían a sí mismos, ¿una buena idea?

Mi intuición es mantener mis clases de datos simples y envolverlas cuando quiero transmitirlas - en clases que las serializan y presentan las clases de emisor y receptor con una interfaz simple que entienden. La alternativa parece ser incluir todo, incluido el fregadero de la cocina, en las clases de datos simples: todas las funciones que puedan funcionar con esos datos, aunque indirectamente. En resumen, el código de manejo de errores de red no me parece pertenecer a una clase de datos simple.

Esto me parece obvio, pero sigo viendo que los desarrolladores ponen métodos Send() en sus clases. Incluso dicen mensaje clases a Send() ellos mismos, lo que parece altamente contrario a la intuición para mí; si escribo una carta en una hoja de papel, no le digo al periódico que se envíe solo. Envuelvo la carta en un sobre y se la entrego al cartero, porque tiene una camioneta y un mapa. ¿Qué piensa la gente?

+0

Puede que le interese una pregunta relacionada: [¿Es una buena convención que una clase realice funciones en sí misma?] (Http://stackoverflow.com/q/3105692/240733) – stakx

+0

Gracias a todos los que respondieron: esto fue mi primera pregunta sobre SO, y ha sido una experiencia muy positiva. – bythescruff

Respuesta

8

Hay una lógica que ver con el artículo de la carga útil: ¿cuál es la velocidad del viento ahora?

Hay una lógica que ver con la interpretación de esa información: ¿podemos acoplar esta nave ahora?

Tiene que ver con la decisión de enviar la carga útil a alguna parte: oh, aquí hay un nuevo valor climático, a alguien le preocupa.

Luego, las cosas de la red real.

Probablemente, la carga útil debe ser capaz de serializarse y deserializarse. No veo que el resto sea la preocupación de la carga útil. Debe haber un lugar mejor para Send(). No menos importante porque puede elegir enviar varios objetos de carga al mismo tiempo, y no todos pueden enviarse entre sí.

5

He estado yendo y viniendo en este tipo de preguntas de diseño varias veces en mi carrera. En este momento, estoy donde pareces, principalmente porque hago un montón de SOA en mi vida actual, y termino escribiendo MUCHAS clases que solo existen para ser serializadas dentro y fuera de varias formatos de conexión, principalmente XML y JSON.

Cuando te mueves al mundo de los "servicios", las clases suelen ser solo representaciones de datos que se envían y reciben. Por lo general, dividí mis clases en dos categorías lógicas, "clases que contienen datos" y "clases que hacen cosas". No sé si soy el único que hace este tipo de cosas, pero ahí es donde estoy.

6

No es una pregunta simple. He realizado proyectos usando ambos enfoques, y en general he estado más feliz trabajando con el enfoque de "modelo inteligente", donde el modelo sabe mucho sobre cómo hacer cosas con sus propios datos.

Uno de los principios que conduce a una buena encapsulación es "contar, no preguntar": si le dice a la clase que se haga algo, nadie excepto la clase en sí necesita saber los detalles de la representación interna de la clase. Eso definitivamente es algo bueno.Además, encuentro que poner la lógica en la clase en sí misma a menudo conduce a una reutilización del código más sencilla: cuando alguien más vaya a usar esa clase, descubrirá rápidamente que ya sabe cómo realizar una operación determinada.

Sin embargo, no quiero que esto conduzca a romper los límites entre mis capas de aplicación. No quiero que un objeto de negocio sepa cómo representarse a sí mismo como HTML: esa es una cuestión de presentación. Entonces, en este caso, diría que la clase debería saber cómo representarse a sí misma de alguna manera canónica, pero no debería saber sobre cosas de la red. La función de envío real debería pertenecer a un servicio.

+0

¡gran publicación! +1. – Armstrongest

+0

Cuando dice: "la clase debe saber cómo representarse a sí misma de alguna manera canónica", ¿quiere decir alguna OTRA manera canónica de sus propiedades? – Mark

+0

@Mark - No estoy seguro. Podría tener sentido para una clase saber cómo serializarse a XML, por ejemplo, pero en el mundo real, a menudo he descubierto que necesito representaciones XML levemente diferentes para diferentes situaciones, y eso parece más como una preocupación de presentación. –

2

La respuesta corta es que depende de los impactos posteriores que desee tratar.

En general, cuando hay dos formas de hacer algo, generalmente significa que ambas maneras tienen sus méritos. Varios ejemplos vienen a la mente (SQL vs. NoSQL, Transmisión automática frente a transmisión manual, Alternancia frente a corriente continua, Lado del cliente frente a Servidor, etc.). El resultado de esto es que estás obligado a atraer a mucha gente de ambos lados con opiniones que tienen mérito.

Así que la pregunta que planteas es cuándo puede un objeto manipular sus propios datos y cuándo debo separarlos.

Personalmente, prefiero mantener simples las estructuras de datos cuya principal responsabilidad es mantener la coherencia de los datos. La responsabilidad de manipular o usar esta información será responsabilidad de otras clases. Esto tiene una tendencia a ayudarme a separar las políticas y la implementación. Por ejemplo, si quiero implementar una política de almacenamiento en caché, solo tengo que visitar la capa que obtiene los datos y no los objetos que almacenan o manipulan los datos.

Por otro lado, esto hace que la API sea más difícil de usar, ya que no siempre es obvio dónde están las cosas. Esto también crea la probabilidad de que se cree la misma política en varias ubicaciones (y cada capa termina implementando el almacenamiento en caché)

Por ejemplo, si los métodos String como Dividir y Unir y Subcadena no fueron fáciles de encontrar en la clase String y en cambio, donde en otro lugar como, por ejemplo, una hipotética clase de Parse, es probable que antes de encontrar esta hipotética clase de Parse hubiera escrito múltiples versiones de esos métodos. Un ejemplo de la vida real es cuando las personas tienen métodos escritos idénticos a los de la clase de Matemáticas porque no lo conocen.

Al final, si no quiere hacer frente al impacto descendente que cambia la forma en que funciona el método Send puede requerir visitar muchas clases, muévalo fuera de de las clases.

Si no desea tratar con personas que implementan accidentalmente su propio método de envío y no desea reforzarlo todo el tiempo, entonces es mejor ponerlo dentro de la clase.

Cuestiones relacionadas