Методические указания по выполнению лабораторных и практических работ по мдк
Скачать 3.25 Mb.
|
Посредник — поведенческий шаблон проектирования, обеспечивающий взаимодействие множества объектов, формируя при этом слабую связанность, и избавляя объекты, от необходимости явно ссылаться друг на друга. Пример из жизни: Общим примером будет, когда вы говорите с кем-то по мобильнику, то между вами и собеседником находится мобильный оператор. То есть сигнал передаётся через него, а не напрямую. В данном примере оператор — посредник. Простыми словами: Шаблон посредник подразумевает добавление стороннего объекта (посредника) для управления взаимодействием между двумя объектами (коллегами). Шаблон помогает уменьшить связанность (coupling) классов, общающихся друг с другом, ведь теперь они не должны знать о реализациях своих собеседников. Разберем пример в коде. Простейший пример: чат (посредник), в котором пользователи (коллеги) отправляют друг другу сообщения. Изначально у нас есть посредник ChatRoomMediator: interface ChatRoomMediator { public function showMessage(User $user, string $message); } // Посредник class ChatRoom implements ChatRoomMediator { public function showMessage(User $user, string $message) { $time = date('M d, y H:i'); $sender = $user->getName(); echo $time . '[' . $sender . ']:' . $message; } } Затем у нас есть наши User (коллеги): class User { protected $name; protected $chatMediator; public function __construct(string $name, ChatRoomMediator $chatMediator) { $this->name = $name; $this->chatMediator = $chatMediator; } public function getName() { 108 return $this->name; } public function send($message) { $this->chatMediator->showMessage($this, $message); } } Пример использования: $mediator = new ChatRoom(); $john = new User('John Doe', $mediator); $jane = new User('Jane Doe', $mediator); $john->send('Привет!'); $jane->send('Привет!'); // Вывод // Feb 14, 10:58 [John]: Привет! // Feb 14, 10:58 [Jane]: Привет! Хранитель — поведенческий шаблон проектирования, позволяющий, не нарушая инкапсуляцию, зафиксировать и сохранить внутреннее состояние объекта так, чтобы позднее восстановить его в этом состоянии. Пример из жизни: В качестве примера можно привести калькулятор (создатель), у которого любая последняя выполненная операция сохраняется в памяти (хранитель), чтобы вы могли снова вызвать её с помощью каких-то кнопок (опекун). Простыми словами: Шаблон хранитель фиксирует и хранит текущее состояние объекта, чтобы оно легко восстанавливалось. Обратимся к коду. Возьмем наш пример текстового редактора, который время от времени сохраняет состояние, которое вы можете восстановить. Изначально у нас есть наш объект EditorMemento, который может содержать состояние редактора: class EditorMemento { protected $content; public function __construct(string $content) { $this->content = $content; } public function getContent() { return $this->content; } } Затем у нас есть наш Editor (создатель), который будет использовать объект хранитель: class Editor { protected $content = ''; public function type(string $words) { $this->content = $this->content . ' ' . $words; } public function getContent() 109 { return $this->content; } public function save() { return new EditorMemento($this->content); } public function restore(EditorMemento $memento) { $this->content = $memento->getContent(); } } Пример использования: $editor = new Editor(); // Печатаем что-нибудь $editor->type('Это первое предложение.'); $editor->type('Это второе.'); // Сохраняем состояние для восстановления : Это первое предложение. Это второе. $saved = $editor->save(); // Печатаем ещё $editor->type('И это третье.'); // Вывод: Данные до сохранения echo $editor->getContent(); // Это первое предложение. Это второе. И это третье. // Восстановление последнего сохранения $editor->restore($saved); $editor->getContent(); //.. : Практическая работа № 1.26. Разработка приложения с использованием текстовых компонентов Цель работы: изучить правила работы текстовыми компонентами Теоретический материал В языках С и C++ файл рассматривается как поток (stream), представляющий собой последовательность считываемых или записываемых байтов. При этом последовательность записи определяется самой программой. C++ Builder позволяет работать с файлами тремя различными способами: Работа с текстовыми компонентами Каждый файл в программе на C++ должен быть связан с некоторым указателем. Этот указатель имеет тип FILE (определен в stdio.h) и используется во всех операциях с файлами. Синтаксис операции следующий: # include < stdio.h > FILE *fin, *fout; Для работы с файлом его необходимо открыть функцией fopen, первый параметр которой содержит имя файла и путь к нему, а второй - режим открытия файла. Функция возвращает указатель на файл. Часто используемые режимы открытия файла: г Открывает файл для чтения 110 r+ Открывает существующий файл для чтения и записи w Создает файл для записи. Если файл уже существует, его содержимое уничтожается w+ Создает файл для чтения и записи. Если файл уже существует, его содержимое уничтожается a Открывает файл для записи данных в конец файла. Если файл отсутствовал, он создается a+ Открывает файл для чтения или записи данных в конец файла. Если файл отсутствовал, он создается После режима может добавляться символ "t" - текстовый файл или "Ъ" -бинарный файл. Если символ не указан, то по умолчанию считается что файл текстовый. Например: fin=fopen("a:\\dat.txt","r"); fout=fopen("a:\\out.txt","w"); При записи обмен происходит не непосредственно с файлом, а с некоторым буфером. Информация из буфера переписывается в файл только приего переполнении или при закрытии файла. После окончания работы с файлом он обязательно должен быть закрыт функцией fclose(FILE *). Если файл не удалось открыть, то возвращается нулевой указатель (NULL). Например: # include < stdio.h > FILE *lw; if (lw=fopen("a.text","r")) == NULL){ Memo1->Lines->Add("Файл не открыт"); return; } fclose(lw); Работа с текстовыми файлами Для записи в текстовый файл наиболее часто используется функция fprintf: int *fprintf(FILE *stream, const char *format[]); где параметр format определяет строку форматирования аргументов, заданных своими адресами. Обычно эта строка состоит из последовательности символов "%", после которых следует символ типа данных: I или i Десятичное, восьмеричное или шестнадцатеричное целое D или d Десятичное целое U или u Десятичное целое без знака E или е Действительное с плавающей точкой s Строка символов с Символ Из отрытого текстового файла можно читать информацию как по строкам. так и посимвольно. Чтение строки осуществляется функцией fgets : char *fgets(char *st, int n, FILE *stream); где st - указатель на буфер, в который считается строка; п - число читаемых символов; stream - указатель на файл. Строка читается до тех пор, пока не будет прочитано п-1 символов, или до конца строки \n. В конце прочитанной строки ставится нулевой символ. Для проверки достижения конца файла используется функция feof(F). Чтение форматированных данных можно осуществлять с помощью функции fscanf: int *fscanf(FILE *stream, const char *format[]); Строка форматирования строится аналогично fprintf. Следует обратить внимание на то, что при чтении данных всегда указываются адреса переменных (&), а не сами переменные. Пример записи и чтения данных из файла: # include < stdio.h > Memo1->Clear(); FILE *lw; // Запись данных в файл if ((lw=fopen("a.text","wf)) == NULL) { 111 Memo1->Lines->Add("Файл не удалось создать"); return; } int num=10; char st[12] = "ИНФОРМАЦИЯ",sr[30]; fprintf(lw,"%s \n В группе %i человек",st, num); fclose(lw); // Чтение данных из файла if ((lw=fopen("a.text","rt")) == NULL) { Memo1->Lines->Add("Файл не удалось открыть "); return; return; } while (!feof(lw)) { fgets(sr,30,lw); if (sr[strlen(sr)-1] =='\n') sr[strlen(sr)-1]=0; Memo1->Lines->Add(sr); } fclose(lw); В C++ определены три класса файлового ввода/вывода: ifstream - входные данные для чтения; ofstream - выходные файлы для записи; fstream - файлы для чтения и записи. Очень удобно применять следующие операции: поместить в поток (<<) и извлечь из потока (>>). Пример программы: #include Memo1->Clear(); // Ввод данных в файл ofstream lw ("a.text"); if (!lw) {Memo1->Lines->Add("Файл не удалось создать "); return;} int num=10; double k=5.67; char s[20] = "ИНФОРМАЦИЯ"; lw << num << '' < Ix » num » k » s; Memo1->Lines->Add(IlntToStr(num)); Memo1->Lines->Add(FloatToStr(k)); Memo1->Lines->Add(s); lx.close(); Помимо этих операции поместить в поток можно еще с помощью функций put и write. Возможности ввода/вывода можно существенно расширить, используя манипуляторы потока. Компоненты TOpenDialog и TSaveDialog Компоненты TOpenDialog и TSaveDialog находятся на странице DIALOGS. Все компоненты этой страницы являются невизуальными, т.е. не видны в момент работы программы. Поэтому их можно разместить в любом удобном месте формы. Оба рассматриваемых компонента имеют идентичные свойства и различаются только внешним видом. После вызова компонента появляется диалоговое окно, с помощью которого выбирается имя программы и путь к ней. В случае успешного завершения диалога имя выбранного файла и маршрут поиска содержатся в свойстве FileName. Для фильтрации файлов, отображаемых в окне просмотра, используется свойство Filter, а для задания расширения файла, в случае, если оно не задано пользователем, - свойство DefaultExt. Если необходимо изменить заголовок диалогового окна, используется свойство Title. Для установки компонентов TOpenDialog и TSaveDialog на форму необходимо на странице Dialogs меню компонентов щелкнуть мышью по пиктограммаме и поставить её в любое свободное место формы. Установка фильтра производится следующим образом. Выбрав соответствующий компонент, дважды щелкнуть по правой части свойства Filter инспектора объектов. Появится окно Filter Editor, в левой части которого записывается текст, характеризующий соответствующий фильтр, а в правой части - маска. Для OpenDialogl установим значения маски, как показано на рис. 7.1. Формат *.dat означает, что будут видны все файлы с расширением dat, а формат *.* - что будут видны все файлы (с любым именем и с любым расширением). 112 Для того чтобы файл автоматически записывался с расширением .dat, в свойстве DefaultExt запишем требуемое расширение - .dat. Аналогичным образом настроим SaveDialogl для текстового файла (расширение .txt). Ход работы Составить программу, вводящую в файл или читающую из файла ведомость абитуриентов, сдавших вступительные экзамены. Каждая запись должна содержать фамилию, курс, группу и средний балл. Вывести список абитуриентов, записанный в файл и прочитанный из файла. Запись произвести в стиле С++ в текстовый файл. Unit1.cpp #define n 5 //ограничим число студентов struct stud { char fam[15]; int kurs; int grup; float ball;}; stud st[n],sz[n]; int kol=0; //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender){ if(kol Edit1->Text=""; Edit2->Text=""; Edit3->Text=""; Edit4->Text=""; Label5->Caption="Число записей "+IntToStr(kol+1); kol++; } 113 else Button1->Enabled=false; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) {int i=0; Memo1->Clear(); ifstream in("z1.txt"); if(!in) {ShowMessage("He удается открыть файл."); } while(!in.eof()) { in>>sz[i].fam; in>>sz[i].kurs; in>>sz[i].grup; in>>sz[i].ball; if (in) { Memo1->Lines->Add(IntToStr(i)); Memo1->Lines->Add(sz[i].fam); Memo1->Lines->Add(IntToStr(sz[i].kurs)); Memo1->Lines->Add(IntToStr(sz[i].grup)); Memo1->Lines->Add(FloatToStrF(sz[i].ball,ffGeneral,5,3)); i++; } } in.close(); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) {int i; AnsiString aaa; Memo2->Clear(); //ofstream out("z1.txt"); ofstream out("z1.txt",ios::app); for (i=0; i Memo2->Lines->Add(IntToStr(st[i].kurs)); Memo2->Lines->Add(IntToStr(st[i].grup)); Memo2->Lines->Add(FloatToStrF(st[i].ball,ffGeneral,5,3)); } out.close(); } //--------------------------------------------------------------------------- Практическая работа № 1.27. Разработка приложения с несколькими формами Цель работы: изучить способ разработки приложений с несколькими формами Ход работы 1. Создайте новый проект, выбрав в главном меню пункт File / New Application. 2. Измените значение свойства Name на MainForm, а свойства Caption— на Multiple Forms Test Program. 3. Сохраните проект. Дайте модулю имя Main, а проекту — имя Multiple. 4. Теперь поместите в форму кнопку (Button). Присвойте свойству Name значение ShowForm2, а свойству Caption — значение Show Form 2. 5. Выберите в главном меню пункт File / New Form (или щелкните на кнопке New Form панели инструментов), чтобы создать новую форму. После создания новая форма будет иметь имя Form1 и разместится точно поверх главной формы. Надо, чтобы новая форма имела меньший размер и была более-менее отцентрирована относительно главной формы. 6. Измените размер и положение новой формы так, чтобы она была примерно в два раза меньше главной формы и располагалась в ее центре. Для перемещения формы используйте строку заголовка. Размер можно изменить перетаскиванием нижнего правого угла. 7. Измените значение свойства Name новой формы на Second_.__114_9._Выберите_компонент_Label'>SecondForm, а свойства Caption — на A Second Form. 8. Выберите в главном меню пункт File / Save (или щелкните на кнопке Save File панели инструментов) и сохраните файл под именем Second. 114 9. Выберите компонент Label и поместите его в новую форму. Измените текст свойства Caption на This is the second form. Измените размер и цвет текста. Отцентрируйте сообщение относительно формы. Теперь ваша форма должна выглядеть примерно как на рис. 3.1. Рис. 3.1 Вид формы к этому моменту 10. Щелкните на главной форме. Обратите внимание, что вторая форма теперь закрыта главной формой. Дважды щелкните на кнопке Show Form 2. На экране появится окно редактора кода и курсор будет размещен как раз там, где вам нужно начинать ввод текста. 11. Введите текст, приведенный ниже (вам нужно набрать только одну строку в скобках): 12. Запустите программу Вы получили сообщение об ошибке SecondForm'>Undefined symbol 'SecondForm' (He определено обозначение 'SecondForm'). Странно... SecondFormдолжно быть правильным именем, ведь именно это имя мы дали второй форме... Дайте подумать... Ara! Вспомните, что у нас есть два исходных файла с соответствующими заголовками. Но в модуле MainForm нет объявления переменной SecondForm (которая является указателем на экземпляр класса TSecondForm). Мы должны указать, где расположено объявление класса. Для этого нужно включить заголовочный файл для SecondForm в исходный файл MainForm с помощью директивы #include. Переключитесь в окно редактора кода и щелкните на вкладке Main.cpp для отображения модуля главной формы. Перейдите к началу файла. Первые несколько строк должны выглядеть следующим образом: 115 Вы видите, что сюда включен заголовочный файл Main.h, но нет файла Second.h, потому что мы не давали указания C++Builderвключить этот файл. Давайте сделаем это сейчас. 1. Выберите в главном меню пункт File / Include Unit Hdr. На экране появится диалоговое окно Include Unit, показанное на рис. 3.2. Рис.3.2 Диалоговое окно Include Unit 2. Перед вами находится список доступных модулей. В данном случае единственным модулем в списке является Second. Щелкните на имени Second, а затем на кнопке ОК, чтобы закрыть диалоговое окно. Диалоговое окно Include Unit отображает только те модули проекта, которые еще не включены в данный модуль. Включенные модули не содержатся в списке. После щелчка на кнопке OK C++Builder мгновенно добавит в файл директиву #include для Second.h: Теперь в модуль Main включено объявление класса из модуля Second. Щелкните на кнопке Run, чтобы запустить программу. На этот раз компиляция пройдет без задержек и программа заработает. Когда вы щелкнете на кнопке Show Form 2, на экране появится вторая форма. Как видите, C++Builder помогает вам управлять модулями. Вы должны использовать опцию Include Unit Hdr, чтобы обеспечить модулям доступ к объявлениям классов, использующихся в других модулях. Поместите на форму компоненты Label1, Edit, Label2, Button1 и Button2 со страницы Standard палитры компонент как показано на рис.4. |