Это касается не только POLA, но и предотвращения недопустимого состояния как возможного источника ошибок.
Давайте посмотрим, как мы можем предоставить некоторые ограничения для вашего примера без предоставления конкретной реализации:
Первый шаг: не позволяйте ничего вызывать до открытия файла.
CreateDataFileInterface
+ OpenFile(filename : string) : DataFileInterface
DataFileInterface
+ SetHeaderString(header : string) : void
+ WriteDataLine(data : string) : void
+ SetTrailerString(trailer : string) : void
+ Close() : void
Теперь должно быть очевидно, что CreateDataFileInterface.OpenFile
нужно вызывать, чтобы получить DataFileInterface
экземпляр, в который можно записать фактические данные.
Второй шаг: убедитесь, что заголовки и трейлеры всегда установлены.
CreateDataFileInterface
+ OpenFile(filename : string, header: string, trailer : string) : DataFileInterface
DataFileInterface
+ WriteDataLine(data : string) : void
+ Close() : void
Теперь вы должны предоставить все необходимые параметры заранее, чтобы получить DataFileInterface
: имя файла, заголовок и трейлер. Если строка трейлера недоступна до тех пор, пока не будут записаны все строки, можно также переместить этот параметр в Close()
(возможно, переименование метода в WriteTrailerAndClose()
), чтобы, по крайней мере, файл не мог быть завершен без строки трейлера.
Чтобы ответить на комментарий:
Мне нравится разделение интерфейса. Но я склонен думать, что ваше предложение о принудительном применении (например, WriteTrailerAndClose ()) граничит с нарушением SRP. (Это то, с чем я боролся несколько раз, но ваше предложение кажется возможным примером.) Как бы вы ответили?
Правда. Я не хотел больше концентрироваться на примере, чем необходимо, чтобы высказать свою точку зрения, но это хороший вопрос. В этом случае я думаю, что назвал бы это Finalize(trailer)
и утверждал, что это не делает слишком много. Написание трейлера и закрытие - это просто детали реализации. Но если вы не согласны или у вас похожая ситуация, когда она отличается, вот возможное решение:
CreateDataFileInterface
+ OpenFile(filename : string, header : string) : IncompleteDataFileInterface
IncompleteDataFileInterface
+ WriteDataLine(data : string) : void
+ FinalizeWithTrailer(trailer : string) : CompleteDataFileInterface
CompleteDataFileInterface
+ Close()
Я бы на самом деле не делал этого для этого примера, но он показывает, как последовательно выполнять технику.
Кстати, я предположил, что методы на самом деле должны вызываться в таком порядке, например, чтобы последовательно писать много строк. Если это не требуется, я бы всегда предпочел застройщика, как предложил Бен Коттрел .