Несколько раз попытался передать свои ощущения от перехода с процедурной парадигмы на ООП, но все уходило куда-то в эмоциональную сферу, либо растекалось в через чур абстрактных описания. Недавно баловался с небольшим проектом, и меня осенило как правильно передать те "открытия", что я сделал для себя.
Самым простым и наглядным будет демонстрация эволюции небольшого проекта от процедурногоговнокода, до удобного в поддержке ООП проекта.
Самым простым и наглядным будет демонстрация эволюции небольшого проекта от процедурного
Итак, задача: есть файл, котором хранятся сообщения, необходимо реализовать удобный пользовательский интерфейс для просмотра сообщений в этом файле.
Эту задачу я решал в 2007 году. На то время ничего кроме процедурного программирования в Borland C я не знал, поэтому решал так, как мог. Исходный текст я сейчас не трогаю(даже не форматирую), для максимального приближения к задаче поддержки и развития работы с чужим кодом.
Вся реализация занимает 400 строк вместе с комментариями, поэтому этот пример очень удачен для задачи рефакторинга.
Перед начало рассмотрения кода, я поставлю для себя цели, которые необходимо выполнить:
1. Необходимо расширить список поддерживаемых форматов. Вместо одного самописного формата программа должна уметь работать с cvs, xml, json. При этом должна сохраниться поддержка старого формата.
2. Реализовать Windows интерфейс.
3. Расширить функциональность.
4. Покрыть код автотестами.
Для начала рассмотрим существующий код. Есть структура mail, которая может выступать в качестве элемента двухсвязного списка, так же есть куча указателей на начало, текущий элементы, и так же на элементы начала и конца области видимости. Память для "головы" выделяется всегда.
В Main мешанина из выделения памяти, чтения и парсинга файла, запуска GUI.
К сожалению, у меня нет сейчас Borland C, поэтому хорошо, что сохранился exe-шник, который позволил посмотреть как это работает. разу же были обнаружены ошибки и лаги в работе.
//--------------------------------------------------------------------------- struct mail { char adresat[20]; char avtor[20]; char tema[20]; char body[256]; mail *next; mail *prev; }; mail *Head = new mail; mail *Buf; mail *Elem; mail *ViewBegin; mail *ViewEnd; mail *Act; int key; FILE *datafile; mail *AddList(mail *EndList); void mailsplit(char *str); void shell(); void refrash(mail *Begin, mail *Activ); void ViewMail(mail *Activ); void DrawWindow(int p); //--------------------------------------------------------------------------- //TODO: int main(int argc, char* argv[]) { puts("Start:\n"); Head->prev = NULL; Elem = new mail; Head->next = Elem; Elem->next = NULL; strcpy(Head->body, "head"); char buffer[256]; char ch[2]; key = 0; if ((datafile = fopen(".//dmail//mail.dat", "rt")) == NULL) { printf("Cannot open input file.\n"); return 1; } while (key != 1) { fscanf(datafile, "%s ", ch); mailsplit(ch); } fclose(datafile); clrscr(); shell(); //getch(); return 0; } //TODO: mail *AddList(mail *Elem) { Buf = new mail; Buf->next = NULL; Buf->prev = Elem; Elem->next = Buf; return Buf; }; //TODO:dfgdfg void mailsplit(char *str) { char i; char buf[1024]; char ChKey; char *pt; i = str[0]; ChKey = str[1]; if (!(i ^ 35)) { if (!(ChKey ^ 49)) { fgets(buf, 20, datafile); strcpy(Elem->adresat, buf); } if (!(ChKey ^ 50)) { fgets(buf, 20, datafile); strcpy(Elem->avtor, buf); } if (!(ChKey ^ 51)) { fgets(buf, 20, datafile); strcpy(Elem->tema, buf); } if (!(ChKey ^ 52)) { fgets(buf, 256, datafile); strcpy(Elem->body, buf); } if (!(ChKey ^ 48)) { Elem = AddList(Elem); } if (!(ChKey ^ 35)) { key = 1; } } } void shell() { int exitkey; char menukey; exitkey = 1; _setcursortype(_NOCURSOR); ViewBegin = Head->next; ViewBegin->prev = NULL; ViewEnd = ViewBegin; Act = ViewBegin; for (int i = 0; i < 19; i++) { ViewEnd = ViewEnd->next; } DrawWindow(1); window(2, 3, 79, 22); refrash(ViewBegin, Act); while (exitkey) { //refrash(ViewBegin, Act); window(2, 3, 79, 22); menukey = getch(); if (menukey == 27) break; if (menukey == 80) { if (Act == ViewEnd) { ViewEnd = ViewEnd->next; ViewBegin = ViewBegin->next; } if (ViewEnd->next == NULL) { ViewEnd->next = Head->next; } if (Act->next == NULL) { Act->next = Act; } else { Act = Act->next; } refrash(ViewBegin, Act); } if (menukey == 72) { if (Act == ViewBegin) { ViewEnd = ViewEnd->prev; ViewBegin = ViewBegin->prev; } if (ViewBegin->prev == NULL) { ViewBegin->prev = ViewBegin; } if (Act->prev == NULL) { Act->prev = Act; } else { Act = Act->prev; } refrash(ViewBegin, Act); } if (menukey == 13) { DrawWindow(2); ViewMail(Act); window(2, 3, 79, 22); refrash(ViewBegin, Act); } } }; void refrash(mail *Begin, mail *Activ) { clrscr(); mail *elem; elem = new mail; elem = Begin; int index; char *adr, *avt, *tema; int i; for (i = 1; i < 21; i++) { textcolor(15); textbackground(9); if (elem == Activ) textcolor(4); if (elem != NULL) { gotoxy(1, i); for (index = 0; elem->adresat[index] != '\n' ; index++) cprintf("%c", elem->adresat[index]); gotoxy(20, i); cprintf(" | "); for (index = 0; elem->avtor[index] != '\n' ; index++) cprintf("%c", elem->avtor[index]); gotoxy(40, i); cprintf(" | "); for (index = 0; elem->tema[index] != '\n' ; index++) cprintf("%c", elem->tema[index]); puts("\n"); } if (elem == NULL) i = 20; elem = elem->next; } }; void ViewMail(mail *Activ) { int index; int x; char menukey; do { if (menukey == 27) { break; } if (menukey == 77) { if (Activ->next != NULL) Activ = Activ->next; } if (menukey == 75) { if (Activ->prev != NULL) Activ = Activ->prev; } window(10, 10, 70, 20); textbackground(10); textcolor(1); for (index = 0; index < 10; index++) for (x = 0; x < 80; x++) cprintf(" "); gotoxy(2, 2); cprintf("Adresat:"); for (index = 0; Activ->adresat[index] != '\n' ; index++) cprintf("%c", Activ->adresat[index]); cprintf("\n\r"); gotoxy(2, 3); cprintf("Avtor :"); for (index = 0; Activ->avtor[index] != '\n' ; index++) cprintf("%c", Activ->avtor[index]); cprintf("\n\r"); gotoxy(2, 4); cprintf("Tema :"); for (index = 0; Activ->tema[index] != '\n' ; index++) cprintf("%c", Activ->tema[index]); cprintf("\n\r"); gotoxy(2, 5); cprintf("Tetx:"); cprintf("%s \n", Activ->body); menukey = getch(); } while (1); }; void DrawWindow(int p) { int i; char ch; if (p == 1) { window(1, 1, 80, 25); textcolor(112); textbackground(15); ch = 205; for (i = 2; i < 80; i++) { gotoxy(i, 2); cprintf("%c", ch); gotoxy(i, 23); cprintf("%c", ch); } ch = 186; for (i = 2; i < 23; i++) { gotoxy(1, i); cprintf("%c", ch); gotoxy(80, i); cprintf("%c", ch); } ch = 188; gotoxy(80, 23); cprintf("%c", ch); ch = 201; gotoxy(1, 2); cprintf("%c", ch); ch = 187; gotoxy(80, 2); cprintf("%c", ch); ch = 200; gotoxy(1, 23); cprintf("%c", ch); gotoxy(1, 25); cprintf("Menu:Esc - Exit Enter - Open mail"); } if (p == 2) { window(9, 9, 71, 23); textcolor(0); textbackground(15); ch = 205; for (i = 1; i < 63; i++) { gotoxy(i, 1); cprintf("%c", ch); gotoxy(i, 13); cprintf("%c", ch); } ch = 186; for (i = 1; i < 14; i++) { gotoxy(1, i); cprintf("%c", ch); gotoxy(63, i); cprintf("%c", ch); } ch = 188; gotoxy(63, 13); cprintf("%c", ch); ch = 201; gotoxy(1, 1); cprintf("%c", ch); ch = 187; gotoxy(63, 1); cprintf("%c", ch); ch = 200; gotoxy(1, 13); cprintf("%c", ch); gotoxy(1, 14); cprintf(" Menu: Esc - Exit Left/Right - Prev/Next Mail "); } };
Комментариев нет:
Отправить комментарий