¿Se debería favorecer la coherencia sobre la convención de programación?

14

¿Cuando se diseña una clase, se debería favorecer la coherencia en el comportamiento sobre la práctica de programación común? Para dar un ejemplo específico:

Una convención común es esta: si una clase posee un objeto (por ejemplo, lo creó), es responsable de limpiarlo una vez que esté listo. Un ejemplo específico sería en .NET que si su clase posee un objeto IDisposable debería eliminarlo al final de su vida útil. Y si no lo tienes, entonces no lo toques.

Ahora, si observamos la clase StreamWriter en .NET, podemos encontrar en la documentación que cierra el flujo subyacente cuando se está cerrando / eliminando. Esto es necesario en los casos en que StreamWriter se crea una instancia al pasar un nombre de archivo, ya que el escritor crea la secuencia de archivos subyacente y, por lo tanto, necesita cerrarlo. Sin embargo, también se puede pasar en una secuencia externa que el escritor también cierra.

Esto me ha molestado muchas veces (sí, sé que puedes hacer una envoltura que no cierra, pero ese no es el punto), pero al parecer Microsoft ha tomado la decisión de que es más coherente siempre cerrar el flujo, sin importar de dónde venga. .

Cuando me cruzo con un patrón de este tipo en una de mis clases, normalmente creo un indicador ownsFooBar que se establece en falso en los casos en que se inyecta FooBar a través del constructor y, de lo contrario, se cumple. De esta manera, la responsabilidad de limpiarlo se pasa al que llama cuando pasa la instancia explícitamente.

Ahora me pregunto si tal vez la coherencia debería estar a favor de la mejor práctica (o tal vez mi mejor práctica no sea tan buena). ¿Algún argumento a favor o en contra?

Editar para aclarar

Con "coherencia" quiero decir: el comportamiento coherente de la clase que siempre toma posesión (y cierra el flujo) frente a la "mejor práctica" para tomar posesión de un objeto solo si lo creó o transfirió explícitamente la propiedad.

En cuanto a un ejemplo donde es enoying:

Suponga que tiene dos clases (de una biblioteca de terceros) que aceptan una secuencia para hacer algo con ella, como crear y procesar algunos datos:

 public class DataProcessor
 {
     public Result ProcessData(Stream input)
     {
          using (var reader = new StreamReader(input))
          {
              ...
          }
     }
 }

 public class DataSource
 {
     public void GetData(Stream output)
     {
          using (var writer = new StreamWriter(output))
          {
               ....
          }
     }
 }

Ahora quiero usarlo así:

 Result ProcessSomething(DataSource source)
 {
      var processor = new DataProcessor();
      ...
      var ms = new MemoryStream();
      source.GetData(ms);
      return processor.ProcessData(ms);
 }

Esto fallará con una excepción Cannot access a closed stream en el procesador de datos. Está un poco construido pero debería ilustrar el punto. Hay varias formas de solucionarlo pero, sin embargo, siento que trabajo en torno a algo que no debería tener que hacer.

    
pregunta ChrisWue 12.01.2012 - 00:17

4 respuestas

9

También utilizo esta técnica, la llamo 'transferencia', y creo que merece el estado de un patrón. Cuando un objeto A acepta un objeto desechable B como un parámetro de tiempo de construcción, también acepta un booleano llamado 'handoff', (que por defecto es falso) y, si es verdadero, entonces se eliminan las cascadas A para eliminar B.

No estoy a favor de proliferar las elecciones desafortunadas de otras personas, por lo que nunca aceptaría la mala práctica de Microsoft como una convención establecida, ni tampoco consideraría que el ciego de otras personas de las desafortunadas elecciones de Microsoft sea un "comportamiento consistente" de ninguna manera. forma o forma.

    
respondido por el Mike Nakis 12.01.2012 - 01:02
3

Creo que tienes razón, para ser honesto. Creo que Microsoft arruinó la clase StreamWriter, específicamente, por las razones que describe.

Sin embargo, desde entonces he visto muchos códigos donde las personas ni siquiera intentan deshacerse de su propio Stream porque el marco lo hará por ellos, por lo que arreglarlo ahora hará más daño que bien.

    
respondido por el pdr 12.01.2012 - 00:26
2

Iría con consistencia. Como mencionó a la mayoría de las personas, tiene sentido que si su objeto crea un objeto secundario, lo poseerá y lo destruirá. Si se le da una referencia desde el exterior, en algún momento, "el exterior" también tiene el mismo objeto y no debe ser propiedad de él. Si desea transferir la propiedad desde el exterior a su objeto, utilice los métodos Adjuntar / Separar o un constructor que acepte un booleano que deje en claro que la propiedad se transfiere.

Habiendo escrito todo eso para una respuesta completa, creo que la mayoría de los patrones de diseño genéricos no necesariamente caen en la misma categoría que las clases StreamWriter / StreamReader. Siempre he pensado que la razón por la que MS eligió que StreamWriter / Reader se hiciera cargo automáticamente de la propiedad es porque en este caso específico, tener la propiedad compartida no tiene mucho sentido. No puede tener dos objetos diferentes leídos / escritos simultáneamente en la misma secuencia. Estoy seguro de que podrías escribir algún tipo de tiempo compartido determinista, pero eso sería un infierno de un anti-patrón. Así que probablemente es por eso que dijeron, ya que no tiene sentido compartir una transmisión, simplemente asumamos el control. Pero no consideraría que este comportamiento se haya convertido en una convención genérica en todas las clases.

Se podría considerar que Streams es un patrón consistente en el que el objeto que se está pasando no se puede compartir desde el punto de vista del diseño y, por lo tanto, sin ningún indicador adicional, el lector / escritor se hace cargo de su propiedad.

    
respondido por el DXM 12.01.2012 - 03:13
2

Ten cuidado. Lo que piensas como "consistencia" podría ser simplemente una colección aleatoria de hábitos.

"Coordinar interfaces de usuario para la consistencia", SIGCHI Bulletin 20, (1989), 63-65. Lo sentimos, no hay enlace, es un artículo viejo. "... un taller de dos días de 15 expertos no pudo producir una definición de consistencia". Sí, se trata de la "interfaz", pero creo que si piensas en la "coherencia" por un tiempo, encontrarás que tampoco puedes definirla.

    
respondido por el Bruce Ediger 12.01.2012 - 03:30

Lea otras preguntas en las etiquetas