2009-04-02 13 views

Respuesta

14

Un constructor es una función también, ¿por qué diferenciar?

La creación de un objeto implica que se han realizado todas las comprobaciones de integridad. Es perfectamente razonable comprobar los parámetros en un constructor y lanzar una excepción una vez que se ha detectado un valor ilegal.

Entre todo esto, simplifica la depuración. Cuando su programa arroja una excepción en un constructor, puede observar un seguimiento de la pila y, a menudo, ver de inmediato la causa. Si retrasa el cheque, tendrá que investigar más para detectar qué evento anterior causa el error actual.

2

Siempre es mejor tener un objeto totalmente construido con todas las invariantes "satisfechas" desde el principio. Tenga cuidado, sin embargo, de arrojar excepciones desde el constructor en lenguajes no administrados ya que eso puede provocar una pérdida de memoria.

1

Si arroja el constructor, es más probable que la traza de pila muestre de dónde provienen los valores incorrectos.

0

Estoy de acuerdo con sharptooth en el caso general, pero a veces hay objetos que pueden tener estados en los que algunas funciones son válidas y otras no. En estas situaciones, es mejor posponer los controles a las funciones con estas dependencias particulares.

Por lo general, querrá validar en un constructor, aunque solo sea porque eso significa que sus objetos siempre estarán en un estado válido. Pero algunos tipos de objetos necesitan verificaciones específicas de funciones, y eso también está bien.

+0

Es lo mismo. Es cierto que no todos los métodos pueden invocarse legalmente en cualquier estado de objeto. Pero también a menudo se pueden identificar las combinaciones de valores de parámetros que pueden unirse en el constructor y arrojar excepciones si se presentan otras combinaciones. – sharptooth

+0

Además, si su objeto tiene algunos métodos que siempre son válidos y otros que no, puede considerar si su objeto es demasiado grande. ¿Tal vez debería dividirse? – sleske

2

Siempre forzar valores en constructores. Si los usuarios no pueden molestarse en seguir las reglas, simplemente los hago cumplir silenciosamente sin decírselos.

Por lo tanto, si pasan un valor de 107%, lo estableceré en 100%. Solo dejo en claro en la documentación que eso es lo que sucede.

Solo si no hay una coacción lógica evidente, les devuelvo una excepción. Me gusta llamar a esto el "principal de la mayor sorpresa para los demasiado perezosos o estúpidos para leer la documentación".

+0

suena interesante, pero ¿esto no conduce a un código que se comporta inesperadamente algunas veces? – Homes2001

+0

Sí, pero solo para aquellos que no han leído el doco :-) – paxdiablo

+0

uhm ... Creo que esto puede llevar a un código difícil de usar/comprender: hay muchos casos en los que me sería difícil detectar el "obvia coerción lógica" –

0

Esta es una pregunta difícil. He cambiado mis hábitos relacionados a esta pregunta varias veces en los últimos años, así que aquí están algunas ideas que vienen a la mente:

  • Comprobación de los argumentos en el constructor es como la comprobación de los argumentos a favor de un método tradicional ... entonces no me gustaría diferenciar aquí ...
  • Verificar los argumentos de un método por supuesto ayuda a asegurar que los parámetros pasados ​​sean correctos, pero también introduce mucho más código que tiene que escribir, lo que no siempre vale la pena en mi opinión ... Especialmente cuando escribes métodos cortos que delegan con bastante frecuencia a otros métodos, supongo que terminarías con el 50% de tu código simplemente haciendo verificaciones de parámetros ...
  • Furthermor Considero que muy a menudo cuando escribe una prueba unitaria para su clase, no quiere tener que pasar parámetros válidos para todos los métodos ... Muy a menudo tiene sentido pasar solo aquellos parámetros importantes para el caso de prueba actual. , por lo que tener cheques lo retrasaría en la escritura de pruebas unitarias ...

Creo que esto realmente depende de la situación ...Lo que terminé es solo escribir comprobaciones de parámetros cuando sé que los parámetros provienen de un sistema externo (como entradas de usuario, bases de datos, servicios web, o algo así ...). Si los datos provienen de mi propio sistema, no escribo pruebas la mayor parte del tiempo.

+0

Acerca de su tercer punto: ¿por qué le gustaría probar algo que nunca sucederá? Si comprueba los parámetros en el constructor, los valores nunca serán el valor incorrecto. Entonces no tienes que probar allí. Solo prueba el constructor con los parámetros incorrectos. –

0

Siempre trato de fallar lo antes posible. Así que definitivamente verifico los parámetros en el constructor.

+0

"Siempre trato de fallar lo antes posible" = "int main (void) {raise (6); ...}"? :-) – paxdiablo

+0

Al menos compiló :) – idstam

0

En teoría, el código de llamada siempre debe garantizar que se cumplan las condiciones previas antes de llamar a una función. Lo mismo vale para los constructores.

En la práctica, los programadores son flojos y, para estar seguros, es mejor seguir controlando las condiciones previas. Las aseveraciones son útiles allí.

Ejemplo. Disculpen mi sintaxis aparato ortopédico no rizado:

// precondition b<>0 
function divide(a,b:double):double; 
begin 
    assert(b<>0); // in case of a programming error. 
    result := a/b; 
end; 

// calling code should be: 
if foo<>0 then 
    bar := divide(1,0) 
else 
    // do whatever you need to do when foo equals 0 

Por otra parte, siempre se puede cambiar las condiciones previas. En el caso de un constructor esto no es realmente útil.

// no preconditions.. still need to check the result 
function divide(a,b:double; out hasResult:boolean):double; 
begin 
    hasResult := b<>0; 
    if not hasResult then 
    Exit; 
    result := a/b; 
end; 

// calling code: 
bar := divide(1,0,result); 
if not result then 
    // do whatever you need to do when the division failed 
+0

Espera un minuto, eso no es solo C sin llaves. ¡Es Pascal! Cuidado chicos, tiene un compilador de Pascal. Corran por sus vidas. – paxdiablo

0

Falla siempre tan pronto como sea posible. Un buen ejemplo de esta práctica se muestra en el tiempo de ejecución. * si intenta utilizar un índice no válido para una matriz, obtendrá una excepción. * la fundición falla inmediatamente cuando no se intenta en una etapa posterior.

Imagínese qué es un código de desastre si un molde dañado permanece en una referencia y cada vez que intente utilizarlo obtendrá una excepción. El único enfoque sensato es fallar lo antes posible y tratar de evitar el estado malo/inválido lo antes posible.

Cuestiones relacionadas