2010-08-11 17 views
5

Me encontré con el siguiente fragmento de código durante una revisión del código.Devolviendo un nuevo objeto vs modificando uno pasado como un parámetro

Mi intuición me dice que esto no está siguiendo el OOP correcto.

Estoy pensando que, en cambio, el método LoadObject debería devolver un nuevo objeto SomeObject, en lugar de modificar el que se pasó a él. Aunque realmente no puedo encontrar una explicación adecuada de por qué esto es mejor.

¿Mi solución es mejor? y si es así ¿por qué? específicamente, ¿qué principios o estándares de OOP se rompen en el ejemplo de código dado (si corresponde)?

public void someMethod() 
    { 
     ... 
     var someObject = new SomeObject(); 
     LoadSomeObject(reader,someObject); 
    } 

    private void LoadSomeObject(SqlDataReader reader, SomeObject someObject) 
    { 
     someObject.Id = reader.GetGuid(0); 
    } 
+0

Parece que también estás mutando 'SqlDataReader'. –

Respuesta

1

No soy un gurú de OO, así que tómalo con un grano de sal.

  1. objetos deberían controlarse/definir su comportamiento ellos mismos en la medida de lo posible. El razonamiento detrás de esto es obvio si alguna vez se dirige de acoplamiento flojo. Es muy posible que sea la mejor decisión de diseño mover los detalles de LoadSomeObject a la implementación de SomeObject, pero eso es difícil de analizar para un ejemplo general.

  2. El estado mutable está perfectamente bien en cualquier código imperativo (incluido el código OO), es una "característica" central de estos paradigmas. OTOH, el estado inmutable tiene ventajas indelebles (supongo que tenemos algunas preguntas sobre este tema aquí, de lo contrario pregúntale a cualquier defensor de PF), y tener algunos objetos inmutables no es especialmente no OO.

Editar: También puede pasar el lector al constructor de SomeObject.

+0

¿Alguna razón en particular fue aceptada sobre la respuesta de Russjudge con 4 veces más votos hacia arriba? – delnan

8

No hay nada de malo en la forma en que se escribe el código, ya que solo está modificando una propiedad en algún objeto.

Sin embargo, sería igual de correcto crear algún objeto dentro de LoadSomeObject y devolverlo.

En este punto, ambas opciones son igual de correctas.

0

De cualquier manera es perfectamente aceptable, pero las consideraciones sobre lo que desea hacer con el objeto devuelto entran en juego al decidir cuál es el adecuado para su situación particular. Inmutabilidad, es decir, crear una nueva instancia en cada operación es cómo se manejan las cadenas en .NET.

Un método de copia obviamente tendría que devolver una copia. Donde, como un método que funciona en un objeto singleton, por ejemplo, que es retenido por una referencia global no sería conveniente devolver un nuevo objeto, ya que los cambios pueden perderse.

0

Si LoadSomeObject va a devolver un nuevo SomeObject, es posible que desee cambiar el nombre del método para evitar confusiones. Tal vez a NewAndLoadSomeObject?

0

Estoy de acuerdo con su intuición, que se siente un poco apagado en la mayoría de los casos. Estoy de acuerdo en que devolver algo es mejor, ya que solo deja en claro que algo está siendo modificado. Al ver que se usa un valor devuelto, se aclara inmediatamente lo que está sucediendo.

creo que esto se siente un poco mejor, aunque (en la mayoría de los casos de todos modos):

public void someMethod() 
{ 
    ... 
    var someObject = new SomeObject(); 
    someObject.Load(reader); 
} 

Y entonces, evidentemente, en la clase SomeObject, que tendría

public void Load(SqlDataReader reader) 
{ 
    this.Id = reader.GetGuid(0); 
} 

La idea es favor de métodos de instancia sobre los estáticos. ¿Por qué molestarse en crear un objeto y pasar sus datos cuando solo puede hacer que el objeto opere sobre sus propios datos?

1

No existe el concepto OO universal, que está en conflicto con un código como ese. Pero más adelante descubrirá que es difícil recopilar y comprender cómo manipular las instancias de SomeObject si no sigue algunos principios de diseño. Tal vez manera más fácil para el arrancador es separar dos tipos principales de procedimientos:

  • Funcional - que está diseñado para crear nuevas instancias y no pueden mutar y otros objetos.
  • Método: diseñado para cambiar el estado de su instancia de host.

Así buena idea aquí, si desea separar SomeObject manipular la lógica es la creación de tipo SomeObjectBuilder con

public void loadFromReader(SqlDataReader reader) 

método y

pública SomeObject getValue()

propiedad

Cuestiones relacionadas