Спроектировать библиотеку ввода/вывода, основанную на применении паттерна Decorator. Центральным элементом библиотеки должен быть интерфейс потока. Этот интерфейс должен реализовываться в нескольких конкретных классах, предназначенных для записи на различные устройства (в файл, в память, в строку). Должна быть возможность применения модификаторов (буферирование, кодирование, сжатие) к любому потоку, причем, следует учесть, что к потоку может применяться произвольное количество модификаторов. Предусмотреть также возможность определения пользователем библиотеки собственных модификаторов потока, и обеспечить удобное их использование, наряду с имеющимися изначально в проекте.
Замечание | |
---|---|
Все перечисленные задачи решаются правильным применением паттерна Decorator. Фактически, Вам необходимо выделить нужные классы, и определить роль каждого класса в паттерне. |
Необходимо реализовать только те классы, которые непосредственно отвечают за ввод из файла, вывод в файл и сжатие потока. Для реализации сжатия следует использовать библиотеку zlib, которую можно скачать с http://www.zlib.net/.
На самом нижнем уровне вывод осуществлять с помощью функций open()
,
read()
,write()
,close()
, описанных в
заголовочном файле io.h
.
При возникновении ошибки (например, невозможности записи в поток) следует генерировать исключение
(exception), причем, лучше всего, если класс
исключения будет производным от std::exception
.
Возможно, по меньшей мере, два подхода по разделению обязанностей чтения и записи между классами. Либо вся эта функциональность может реализовываться одним классом потока, либо могут быть предусмотрены разные классы для ввода и для вывода. Решение о том, какого подхода будете придерживаться Вы принимать, безусловно, Вам. Однако, во втором случае, вероятно, придется реализовывать раздельно декораторы для входных и выходных потоков, что приведет к удвоению числа классов в библиотеке.
Интерфейс(ы) потока ввода/вывода должен включать, как минимум, две операции: побайтовый ввод/вывод, и ввод/вывод последовательности байт заданного размера.
Для защиты лабораторной работы необходимо представить:
Разработанная библиотека должна допускать, к примеру, такое использование:
/*...*/ int main() { /* Создается поток записи в файл (FileStream) и настраивается * на работу с файлом "output.txt". * Создается экземпляр DeflaterStream, добавляющий буферизацию * для связанного с ним потока. Непосредственно при создании * DeflaterStream связывается с экземпляром FileStream * (в данном случае, указатель на созданный FileStream просто * передается конструктору DeflaterStream в качестве аргумента). */ Stream *os = new DeflaterStream( new FileStream("output.txt", WRITE) ); /* Создается еще один поток, на этот раз для * чтения из файла. */ Stream *is = new InflaterStream( new FileStream("input.txt", READ) ); char buf[1024]; /* Здесь предполагается, что операция read потока возвращает * количество считанных символов. В спроектированной Вами библиотеке * это может быть не так, но, в любом случае, должна быть какая-то * возможность узнать это количество. */ int qty = is->read(&buf[0], 1024); os->write('l'); // вывод в поток одного символа os->write(&buf[0], qty); // вывод в поток указанного количества // символов delete os; delete is; return 0; }