Não se trata apenas de POLA, mas também de impedir o estado inválido como uma possível fonte de erros.
Vamos ver como podemos fornecer algumas restrições ao seu exemplo sem fornecer uma implementação concreta:
Primeiro passo: não permita que nada seja chamado antes de um arquivo ser aberto.
CreateDataFileInterface
+ OpenFile(filename : string) : DataFileInterface
DataFileInterface
+ SetHeaderString(header : string) : void
+ WriteDataLine(data : string) : void
+ SetTrailerString(trailer : string) : void
+ Close() : void
Agora deve ser óbvio que CreateDataFileInterface.OpenFile
deve ser chamado para recuperar uma DataFileInterface
instância em que os dados reais podem ser gravados.
Segunda etapa: verifique se os cabeçalhos e os trailers estão sempre definidos.
CreateDataFileInterface
+ OpenFile(filename : string, header: string, trailer : string) : DataFileInterface
DataFileInterface
+ WriteDataLine(data : string) : void
+ Close() : void
Agora você deve fornecer todos os parâmetros necessários antecipadamente para obter DataFileInterface
: nome do arquivo, cabeçalho e trailer. Se a sequência de trailer não estiver disponível até que todas as linhas sejam gravadas, você também poderá mover esse parâmetro para Close()
(possivelmente renomeando o método para WriteTrailerAndClose()
) para que o arquivo pelo menos não possa ser concluído sem uma sequência de trailer.
Para responder ao comentário:
Eu gosto da separação da interface. Mas estou inclinado a pensar que sua sugestão sobre aplicação (por exemplo, WriteTrailerAndClose ()) está prestes a violar o SRP. (Isso é algo com o qual luto várias vezes, mas sua sugestão parece ser um exemplo possível.) Como você reagiria?
Verdade. Não queria me concentrar mais no exemplo do que o necessário para expressar minha opinião, mas é uma boa pergunta. Nesse caso, acho que chamaria isso Finalize(trailer)
e argumentaria que não faz muito. Escrever o trailer e fechar são meros detalhes de implementação. Mas se você não concorda ou tem uma situação semelhante em que é diferente, aqui está uma solução possível:
CreateDataFileInterface
+ OpenFile(filename : string, header : string) : IncompleteDataFileInterface
IncompleteDataFileInterface
+ WriteDataLine(data : string) : void
+ FinalizeWithTrailer(trailer : string) : CompleteDataFileInterface
CompleteDataFileInterface
+ Close()
Na verdade, eu não faria isso neste exemplo, mas mostra como realizar a técnica consequentemente.
A propósito, presumi que os métodos realmente devam ser chamados nessa ordem, por exemplo, para escrever sequencialmente muitas linhas. Se isso não for necessário, eu sempre preferiria um construtor, como sugerido por Ben Cottrel .