Заметки, идеи и мысли автора, обзор кода, алгоритмов, инструментов.

понедельник, 4 января 2010 г.

Скажем НЕТ! - оператору "GoTo"

Помню как только мы прошли для галочки оператор goto (ГоуТу), по учебной программе колледджа, я как бы его не взлюбил, особенно после того как преподавательница нам намекнула о том что его лучше не использовать и что его использование считается дурным тоном программирования.

Так вот дело понятное, сейчас работая с такими довольно массивными проектами написанными на Дельфи, иногда мне встречаются модули в которых используются эти самые операторы. Блин, я больше всего не люблю изменять такие модули(хорошо что их всего парочка), потому что как правило в них исправляя одну проблему появляется новых две, ведь кода в них не мало, писался этот код несколькими программистами до меня, и чтобы понять всю логику таких модулей приходится тратить не один час, а иногда не один день, и уж поверьте это удручает, поэтому начинающим программистам чисто так по человечески скажу - не привыкайте использовать этот оператор с "малых лет".

Теперь немного ближе к теме. Прошли мы значит в колледже этот оператор, учитель сказал нам что это "кака", но вот проходит пара лекций и вдруг нам дается официальное разрешение использовать данный оператор для создания цветового меню. Как же я тогда в душе злился. Я помню тогда подошел к преподавателю и показал ей свой вариант решения задачи, где не нужно было использовать никакого оператора Goto, и при этом все прекрасно работало, но в ответ получил примерно следующую фразу "Молодец, ты можешь так придумать, а другие не могут, поэтому пусть делают как умеют". Я помню пытался одногруппникам донести свой вариант, и объяснить почему так лучше, но понимание нашел лишь у пары человек. Остальным было пофиг.

Обычная реализация данного меню состояла в том что при нажатии определенных клавиш оператор Goto переносил курсор в нужный кусок кода который в свою очередь делал какие-то перерисовки и выполнял определенные действия и ждал следующего нажатия при надобности чтобы в очередной раз перейти в другой кусок кода. Когда одногрупники стали использовать такой вариант в своих более менее весомых(больших) программах, разобраться в их коде было сложно, и когда меня просили помочь с чем-то, я первые раза три отправлял таких лесом и рекомендовал привести код в порядок ибо было мне в лом разбираться в "стоге сена".

А теперь демонстрирую свой вариант реализации цветого меню в Паскале, с возможностью строить многоуровневые меню. Кстати в данном варианте все ещё есть недостатки, то есть, имеются "штуки" которые можно сделать ещё лучше, но это вы уж сами :)
Код моего варианта, с примером использования:

Uses crt;
 var str,str2,STR3:array[1..20]of string;
     I:integer;
     k:char;
     X11,X22:integer;

{Универсальная процедура для вывода вертикального меню, параметры описаны ниже}
Procedure menu(kl,XX,YY:integer; pun:array of string;
          fon,txt,fon1,txt1:integer;var key:char; X1:integer);
    {колич.пунк.}{место по Х}{место поУ}{имена пунк.}{нор.фон}
    {нор.текст}{выд.фон}{выд.текст}{код клавиши}{положение курсора}
      begin
       textbackground(fon);
        textcolor(txt);
       { ClrScr;}
{         GotoXY(XX,YY); Кому надо можно использовать рамку, но для вложенных менюх такой вариант не пойдет.
            write('г============МЕНЮ============¬');
          For I:=1 to kl+1 do begin
          GotoXY(XX,YY+i);
            write('¦                            ¦');
          end;
           GotoXY(XX,YY+i);
            write('L============================-');}
              For I:=1 to kl do begin
                GotoXY(XX+1,YY+i);
                  write(pun[i]);
              end;
              x1:=1;
            repeat
              if key=#80 then X1:=X1+1;
              if key=#72 then X1:=X1-1;
                     if X1>KL then X1:=1;
                     if X1<1 then X1:=KL;
              For I:=1 to kl do begin
               If x1=i then begin textcolor(txt1); textbackground(fon1); end
                 else begin textcolor(txt); textbackground(fon); end;
                   GotoXY(XX+1,YY+i);
                     write(pun[i]);
              end;
            key:=#0;
            key:=readkey;
            Until (key=#13)or(key=#27);
      end;
    {Процедура для вывода горизонтального меню, для отдельных частных случаев требует некоторой правки.
    Желающие могут усовершенствовать до универсального вида.}
        Procedure Main_menu(var Y1:integer;Key:char);
             begin
             Y1:=1;
             repeat
             GotoXY(1,1);
               write('Файлы БД    Задачи    Выход');
                 if key=#75 then Y1:=Y1-1;
                 if key=#77 then Y1:=Y1+1;
                   if Y1>3 then Y1:=1;
                   if Y1<1 then Y1:=3;
         GotoXY(1,1);
          If y1=1 then begin textcolor(15); textbackground(4); end
            else begin textcolor(15); textbackground(9); end;
             write(' Файлы БД  ');
          GotoXY(12,1);
           If y1=2 then begin textcolor(15); textbackground(4); end
            else begin textcolor(15); textbackground(9); end;
             write('  Задачи  ');
          GotoXY(22,1);
           If y1=3 then begin textcolor(15); textbackground(4); end
            else begin textcolor(15); textbackground(9); end;
             write(' Выход ');
            key:=#0;
            key:=readkey;
            Until key=#13;
           end;
     
      Begin
    {А вот и простейший пример использования данных процедур в комбинации.}
      ClrScr;
    {Заполняем массив пунктов первого меню}
      str[2]:='  Файл 1   ';
      str[3]:='  Файл 2   ';
      str[4]:='  Файл 3   ';
      str[5]:='  Файл 4   ';
      str[6]:='  Файл 5   ';
      str[7]:='  Выход    ';
   
    {Заполняем массив пунктов второго меню}
      str2[2]:=' Задача 1 ';
      str2[3]:=' Задача 2 ';
      str2[4]:=' Задача 3 ';
      str2[5]:=' Задача 4 ';
      str2[6]:=' Задача 5 ';
      str2[7]:=' Выход    ';

    {Заполняем массив пунктов третье меню(вложенность третьего уровня)}
      str3[2]:=' Ввод в файл             ';
      str3[3]:=' Дополнение файла        ';
      str3[4]:=' Удаление из файла       ';
      str3[5]:=' Замена компонент файла  ';
      str3[6]:=' Вставка компонент файла ';
      str3[7]:=' Просмотр файла          ';
      str3[8]:=' Выход                   ';
     
      Main_menu(X11,K); {вызовим главное меню(горизонтальное).}
      {Получив    в переменную X11 номер выбранного пункта, вызовим соответствующее подменю.}
      If (X11=1) then
    begin
          Menu(6,0,1,str,9,15,4,3,k,x22);
          If (k=#13) then
            Menu(7,11,X22+1,str3,9,15,4,3,k,x22);
    end;
      if (X11=2) then
        Menu(6,11,1,str2,9,15,4,3,k,x22);

      end.

Код конечно нуждается в хорошем рефакторинге, но сильно строго не судите, писал я его в 2005 году будуче не опытным студентом :) Но в качестве примера сойдет, да и основная мысль думаю ясна. Если все же что-то не понятно постите в комментариях свои вопросы, поясню.
К коду добавлю пару слов. Все операторы Goto были заменены такой конструкцией как процедура/функция, и циклами, на мой взгляд куда лучше чем перемещаться по дублирующим друг друга кускам кода которые в дальнейшем крайне тяжело править. Понятное дело что такие с позволения сказать программы, нужны наверное только студентам и тем кто делает на студентах деньги, но просто не мог смолчать =)

Это не большое отступление так сказать о наболевшем. В следующий раз постараюсь обозреть процесс создания игры-арканойда все на том же добром Турбо-Паскале, а затем уже буду потихоньку прекращать описывать "баяны" написанные на Паскале =)

Комментариев нет:

Отправить комментарий

Постоянные читатели