Ao projetar uma classe, a consistência no comportamento deve ser preferida à prática comum de programação? Para dar um exemplo específico:
Uma convenção comum é a seguinte: se uma classe possui um objeto (por exemplo, ele o criou), é responsável por limpá-lo quando terminar. Um exemplo específico seria no .NET que, se sua classe possuir um IDisposable
objeto, ele será descartado no final de sua vida útil. E se você não o possui, não o toque.
Agora, se olharmos para a StreamWriter
classe no .NET, podemos encontrar na documentação que ela fecha o fluxo subjacente quando está sendo fechada / descartada. Isso é necessário nos casos em que o StreamWriter
instanciado passa um nome de arquivo, pois o escritor cria o fluxo de arquivos subjacente e, portanto, precisa fechá-lo. No entanto, também é possível passar em um fluxo externo que o gravador também fecha.
Isso me incomodou muitas vezes (sim, eu sei que você pode criar um invólucro sem fechamento, mas esse não é o ponto), mas aparentemente a Microsoft tomou a decisão de que é mais consistente sempre fechar o fluxo, não importa de onde ele veio.
Quando encontro esse padrão em uma de minhas classes, geralmente crio um ownsFooBar
sinalizador que é definido como falso nos casos em que FooBar
é injetado pelo construtor e verdadeiro caso contrário. Dessa forma, a responsabilidade de limpá-lo é passada ao chamador quando ele passa a instância explicitamente.
Agora, estou me perguntando se talvez a consistência deva ser favorável às melhores práticas (ou talvez minha melhor prática não seja tão boa)? Algum argumento a favor / contra?
Editar para esclarecimentos
Com "consistência", quero dizer: o comportamento consistente da classe sempre tomando posse (e fechando o fluxo) versus "prática recomendada" para tomar posse de um objeto apenas se você o criou ou transferiu explicitamente a propriedade.
Como um exemplo em que é irritante:
Suponha que você tenha duas classes (de alguma biblioteca de terceiros) que aceitam um fluxo para fazer algo com ele, como criar e processar alguns dados:
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))
{
....
}
}
}
Agora eu quero usá-lo assim:
Result ProcessSomething(DataSource source)
{
var processor = new DataProcessor();
...
var ms = new MemoryStream();
source.GetData(ms);
return processor.ProcessData(ms);
}
Isso falhará com uma exceção Cannot access a closed stream
no processador de dados. É um pouco construído, mas deve ilustrar o ponto. Existem várias maneiras de corrigi-lo, mas, no entanto, sinto que trabalho em torno de algo que não deveria.