Вариант 5. Ввод/вывод с помехоустойчивым кодированием

Стоимость

40 баллов

Описание

Спроектировать библиотеку ввода/вывода, основанную на применении паттерна Decorator. Центральным элементом библиотеки должен быть интерфейс потока. Этот интерфейс должен реализовываться в нескольких конкретных классах, предназначенных для записи на различные устройства (в файл, в память, в строку). Должна быть возможность применения модификаторов (буферирование, кодирование, сжатие) к любому потоку, причем, следует учесть, что к потоку может применяться произвольное количество модификаторов. Предусмотреть также возможность определения пользователем библиотеки собственных модификаторов потока, и обеспечить удобное их использование, наряду с имеющимися изначально в проекте.

[Замечание]Замечание

Все перечисленные задачи решаются правильным применением паттерна Decorator. Фактически, Вам необходимо выделить нужные классы, и определить роль каждого класса в паттерне.

Необходимо реализовать только те классы, которые непосредственно отвечают за ввод из файла, вывод в файл и помехоустойчивое кодирование/декодирование. В качестве алгоритма помехоустойчивого кодирования можно взять любой - например, код Хэмминга, причем, для простоты его можно выровнять по байтам. Например, вполне допустимо кодировать один байт исходной последовательности двумя байтами выходной, причем каждый из двух байт выходной последовательности получать кодированием половины байта исходной последовательности кодом Хэмминга (7,4).

На самом нижнем уровне вывод осуществлять с помощью функций open(), read(),write(),close(), описанных в заголовочном файле io.h.

При возникновении ошибки (например, невозможности записи в поток) следует генерировать исключение (exception), причем, лучше всего, если класс исключения будет производным от std::exception.

Возможно, по меньшей мере, два подхода по разделению обязанностей чтения и записи между классами. Либо вся эта функциональность может реализовываться одним классом потока, либо могут быть предусмотрены разные классы для ввода и для вывода. Решение о том, какого подхода будете придерживаться Вы принимать, безусловно, Вам. Однако, во втором случае, вероятно, придется реализовывать раздельно декораторы для входных и выходных потоков, что приведет к удвоению числа классов в библиотеке.

Интерфейс(ы) потока ввода/вывода должен включать, как минимум, две операции: побайтовый ввод/вывод, и ввод/вывод последовательности байт заданного размера.

Защита

Для защиты лабораторной работы необходимо представить:

  • Работающую программу (причем, описания структур должны быть вынесены в заголовочные файлы, а их определение - в соответствующие .cpp-модули).
  • Диаграмму классов. Для каждого реализованного класса должны быть показаны все операции и атрибуты, причем для каждой операции должна быть показана сигнатура и спецификатор доступа. Для классов, входящих в проект библиотеки, но реализация которых не предусмотрена заданием, можно показать только обязанности
  • За набор юнит-тестов можно получить дополнительные 5 баллов. Юнит тесты должны быть выполнены с применением какой-либо (на ваше усмотрение) платформы юнит-тестирования для C++: Boost::Test, CppUnit, CppUnitLite (самый простой, пожалуй, вариант) и т.п.

Пример

Разработанная библиотека должна допускать, к примеру, такое использование:

/*...*/

int main() {
        /* Создается поток записи в файл (FileStream) и настраивается
         * на работу с файлом "output.txt".
         * Создается экземпляр CoderStream, реализующий
         * помехоустойчивое кодирование для 
         * для связанного с ним потока. Непосредственно при создании
         * CoderStream связывается с экземпляром FileStream
         * (в данном случае, указатель на созданный FileStream просто 
         * передается конструктору CoderStream в качестве аргумента).
         */
       
        Stream *os = new CoderStream(
                               new FileStream("output.txt", WRITE)
                     );

        /* Создается еще один поток, на этот раз для 
         * чтения из файла.
         */
	Stream *is = new DecoderStream(
				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;
}
Сайт управляется системой uCoz