Далее, можно написать простой цикл для вызова метода Draw всех экземпляров объектов, содержащихся в массиве, не проверяя при этом, какая именно фигура хранится в каждом элементе массива. Например:

var ShapeArray: array [1..10] of TShape;

begin

for x := 1 to ShapeCount do

ShapeArray [x].Draw;

В этом и заключается полиморфизм. Коду в цикле достаточно знать лишь тип класса-предшественника, в котором заданы виртуальные методы, замещаемые в производных классах. Во время работы программы в зависимости от того, представитель какого именно класса хранится в обобщённой переменной (в нашем случае в массиве типа TShape), будет вызван метод именно этого производного класса.

1.14 Графика в Delphi

Весь вывод, генерируемый программами в Windows, по своей природе графический.

Когда надо вывести информацию на экран дисплея, Windows представляет в распоряжение пользователя оконно-ориентированную графику. Это означает, например, что каждая форма Delphi рассматривается как отдельная поверхность для рисования. Всё, что рисуется в форме, обрезается по её границам.

начало графических координат формы, т. е. точка с координатами (0,0), находится в верхнем левом углу области рисования окна, известной также как область клиента окна.

Область клиента (client area) окна - это область внутри рамки окна, в которой приложение может выводить текст и графику.

Объекты, рисуемые внутри окна, автоматически обрезаются по его границе. Такой подход гарантирует, что вывод приложения не затронет области клиента других приложений.

НЕ нашли? Не то? Что вы ищете?

Аналогично этому каждый визуальный компонент Delphi, размещаемый на форме, является отдельной и независимой поверхностью рисования. Каждый такой компонент отвечает за прорисовку самого себя, т. е. за вывод текста и графики в области клиента.

1.14.1 Объект Canvas

Для создания графического вывода из программы Delphi пользователь должен взаимодействовать с объектом Canvas. Этот объект инкапсулирует в себе взаимодействие с генератором графики внутри Windows. Этот генератор известен как GDI (Graphic Device Interface). GDI - это набор подпрограмм для вывода графики и связанных с ними структур данных, которые дают возможность приложениям отображать информацию визуально. Прямое взаимодействие с GDI утомительно и чревато ошибками. Концепция Canvas и её реализация в виде стандартного класса TCanvas значительно упрощают использование графики.

Canvas сам по себе является свойством других визуальных объектов Delphi. Если у объекта есть свойство Canvas, на поверхности этого объекта можно рисовать.

Свойство Canvas никогда не делают опубликованным (published). Оно доступно только во время работы приложения. Поэтому управлять свойством можно лишь из программы, написав соответствующий код на Object Pascal.

Свойство Canvas, если оно есть, всегда доступно только для чтения. Это означает, что из программы нельзя назначать различные Canvas своему объекту. На каждом визуальном объекте лежит ответственность за работу со своим Canvas.

О Canvas можно думать как о воображаемом листе бумаги, на котором можно рисовать.

1.14.2 Свойства Canvas

К наиболее важным свойствам класса TCanvas относятся:

1) Pen (перо) - для черчения линий.

2) Brush (кисть) - для заполнения внутренних областей фигур различными цветами и сетками.

3) Font (шрифт) - для вывода текста.

4) Handle (дескриптор) - для прямого доступа к контексту устройства Windows при работе с вызовами GDI на низком уровне.

Класс TCanvas определяется в стандартном модуле Graphics. Для работы с рисунками на уровне пикселов надо использовать публичное свойство Pixels, которое позволяет рассматривать поверхность рисования как двумерный массив пикселов.

Надо везде, где это возможно, использовать встроенные возможности рисования объекта Canvas, а не заниматься управлением цветами индивидуальных пикселов в своём изображении.

1.14.3 Методы объекта Canvas

Наиболее часто используются методы:

1) Rectangle - для черчения прямоугольников и квадратов.

2) Ellipse - для черчения эллипсов и окружностей.

3) MoveTo и LineTo - для черчения прямых линий.

4) Polygon и PolyLine - для черчения соответственно многоугольников и ломаных линий, состоящих из нескольких отрезков.

5) TextOut - вывод текста.

Пример 1. (Rectangle).

Метод Tcanvas. Rectangle определяется следующим образом:

TCanvas = class(TPersistent)

. . .

public

. . .

procedure Rectangle(X1, Y1, X2, Y2: Integer);

. . .

end;

Пример 2. (TexOut)

Метод TexOut объявляется следующим образом:

TCanvas = class(TPersistent)

. . .

public

. . .

procedure TextOut(X, Y: Integer; const Text: String);

. . .

end;

Пример использования метода:

Form1.Canvas. extOut (10,10,’Hello, word!’);

Пример черчения фигур

После создания нового проекта на странице событий Инспектора объекта надо выбрать событие OnPaint и дважды щёлкнуть мышью на колонке значений справа от имени события. В результате создастся скелет метода обработки события TForm1.FormPaint.

Его надо заполнить следующим кодом:

procedure TForm1.FormPaint(Sender: TObject);

var Count, Current, Step: Integer;

R: Trect;

begin

R:= ClientRect;

InflatRect(R,-10,-10);

{Draw Frame and Background}

Canvas. Brush. Color:= clYllow;

Canvas. Pen. Color:= clBlack;

Canvas. Rectangle(R. Left, R. Top, R. Right, R. Bottom);

{Draw horisontal grid}

Step:=15;

Current:=Succ(Step);

Canvas..Pen. Color:=clLime;

while Current<R. Bottom do

begin

Canvas. MoveTo(Succ(R. Left),Current);

Canvas. LineTo (Pred(R. Right),Current);

Inc (Current, Step);

end;

{Draw Vertical Lines}{ На странице блокнота появляется левое поле,}

{ограниченное двумя вертикальными параллельными красными}

{линиями через всю страницу}

Step:=3;

Current:=85;

Canvas. Pen. Color:=clRed;

for Count:=1 to 2 do

begin

Canvas. MoveTo(Current, Succ(R. Top));

Canvas. LinesTo(Current, Pred(R. Bottom));

Inc(Curren, Step);

end;

{Ellipse}

with Canvas do

begin

Pen. Color := clBlack;

Brush. Color := clFuchsia;

Ellipse (230,40,360,60);

Brush. Color := clAgua;

Ellipse (200,40,260,90);

Brush. Color := clPurple;

Ellipse (220,20,300,80);

end;

{Text Label}

with Canvas do

begin

Brush. Style := bsClear; {фон текста будет прозрачным,}

{так что при вычерчивании текста}

{будет виден прежний фон}

TextOut(120,50,’Ellipses’);

Brush. Style := bsSolid; {по умолчанию установлено это }

{значение свойства, что при выводе}

{текста приводит к заполнению}

{фона, ограничивающего текст}

{прямоугольника текущим цветом}

{свойства Canvas. Brush}

end;

end;

end.

1.15 Обработка исключений

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

Исключения (exceptions) - это способ передачи информации об ошибке времени выполнения или о других исключительных ситуациях из того места, которое первым её обнаружило, в код. предусмотренный для обработки таких ситуаций.

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

Когда исключение возбуждено. начинается поиск подходящего обработчика исключений. Когда обработчик найден, управление передаётся ему, никогда не возвращаясь к коду, который возбудил исключение. После выполнения кода обработчика исключений, в зависимости от его типа, либо продолжается выполнение программы с оператора, следующего за обработчиком, либо продолжается поиск другого обработчика исключений.

1.15.1 Конструкция try – finally

Конструкция try - finally обработки исключений занимается защитой ресурсов: - динамической памяти, файлов, ресурсов Windows, объектов. Оператор try - finally гарантирует, что программа выполнит операторы, освобождающие ресурсы, независимо от того, было или нет возбуждено исключение. Если при возбуждении исключения выполнение передаётся блоку try - finally, он не уничтожает это исключение. После того, как выполнится код части finally, исключение пойдёт дальше к следующему подходящему обработчику исключений.

Общий синтаксис блока try - finally:

операторы захвата ресурсов

try

прочие операторы

finally

операторы, освобождающие ресурсы

end;

 
 

Раздел try содержит операторы, которые могут возбудить исключение. Раздел finally содержит операторы, которые освобождают ресурсы. При возбуждении оператором из try - блока управление передаётся в раздел finally, выполняется содержащийся в нём код, после чего поиск обработчика исключения возобновляется. если код в блоке try не возбудил исключения, всё равно выполняется код раздела finally, после чего выполнение программы продолжается с оператора, следующего за блоком try - finally. Независимо от того, что произошло. код в разделе finally всегда будет выполнен при выходе из try- блока.

Пример:

procedure TForm1.TestBtnClick (Sender: TObject);

const Max=100;

var i, j: Integer;

d: ^Integer;

begin

GetMem(d, Max*SizeOf(Integer));

try

j:=0;

for i:=0 Max-1 do

d^:=1000 div j;

ListArray;

Inc(j);

for i:=0 to Max-1 do

d^:=100 div j;

ListArray;

finally

FreeMem(d, Max*SizeOf(Integer));

end;

end;

В try - блоке этого примера создаётся динамический массив, состоящий из 100 целых чисел. Когда оператор деления возбуждает исключение, управление передаётся сначала в раздел finally, в котором освобождается динамическая память, затем - в следующий внешний обработчик исключений, найденный в стеке вызовов. Если бы код в try - блоке мог завершиться, не возбудив исключения, то блок finally, освобождающий динамическую память, был бы выполнен как часть нормального выполнения процедуры.

1.15.2 Конструкция try - except

Оператор try - except является вторым видом обработчика исключений. Код в блоке except выполняется только при возбуждении исключения, но никогда - при нормальной работе программы. В блоке except может быть несколько обработчиков исключений, каждый из которых ориентирован на определённый тип исключения. После выполнения кода блока except исключение уничтожается - процесс поиска в стеке вызовов заканчивается и выполнение программы продолжается с оператора. следующего за оператором try - except.

Общий синтаксис для блока try - except:

try

операторы

except

операторы очистки

end;

Блок try содержит операторы, которые могут возбудить сообщения. Раздел except содержит операторы, выполняющие действия по очистке. Когда в операторе из try - блока возникает ошибка, управление передаётся в раздел except. Если ошибки не возникает, то программа пропускает код раздела except.

Пример:

procedure TForm1.TestBtnClick (Sender: TObject);

var z, y,x: Integer;

begin

x:=100; y:=0;

try

z:= x div y;

except

z:=-1;

end;

MessageDlg (‘z= ‘+IntToStr(z), mtInformation, [mbOK],0);

end;

В этом примере в диалоговом окне сообщений выводится значение z=-1.

За ключевым словом except обычно следует список обработчиков исключений, состоящий из операторов on - do.

Общий синтаксис операторов on - do:

try

операторы

except

on классИсключений1 do begin

Группа #1 операторов очистки

end;

on классИсключений2 do begin

Группа #2 операторов очистки

end;

on классИсключений3 do begin

Группа #3 операторов очистки

end;

остальные on - do операторы

else

Группа операторов очистки по умолчанию

end;

Когда в try - блоке возникает исключение, управление передаётся разделу except, в котором тип класса в каждом из операторов on-do проверяется на совместимость с типом текущего экземпляра исключения. Тип оператора on-do совместим с экземпляром исключения в том случае, если он либо идентичен типу экземпляра объекта исключения, либо является его производным типом. Если в разделе except нет подходящего оператора on-do, но есть раздел else, выполняется его код. Если же нет ни совместимого по типу оператора on-do, ни раздела else, поиск обработчика исключения продолжается в следующем внешнем try - блоке стека вызовов.

Пример:

procedure TForm1.TestBtnClick(Sender: TObject);

var z, y,x: Integer;

begin

x:=100; y:=0;

try

z:= x div y;

except

on EDivByZero do z:=-1;

end;

MessageDlg (‘z= ‘+IntToStr(z), mtInformation, [mbOK],0);

end;

В этом примере одно целое число делится на другое. Если оператор деления возбуждает исключение, то управление передаётся коду раздела except. В этом разделе есть оператор on EDivByZero do, который соответствует ошибке деления на нуль. Оператор, связанный с этим разделом on - do, присваивает переменной z значение -1. После этого код выводит значение переменной z в диалоговом окне сообщений.

Delphi позволяет использовать вложенные обработчики try - finally и try - except. Вложенные обработчики дают возможность реализовать сложные схемы обработки исключений.

Общий синтаксис вложенных try - блоков:

try

операторы

try

операторы

{except | finally}

код очистки

end;

{except | finally}

код очистки

end;

Этот синтаксис показывает, как можно вкладывать друг в друга блоки try - except, try - finally и их комбинации. Блоки исключений можно вкладывать друг в друга в любой комбинации и на любую глубину.

Рекомендации: следует использовать оператор on - do для обеспечения специфического отклика на определённые исключения.

Не следует систематически использовать раздел else, поскольку его операторы завершают обработку непредусмотренных ошибок. То есть, разделом else рекомендуется пользоваться только тогда, когда в самом деле известно, что происходит в коде.

Перечислим некоторые исключения библиотеки времени выполнения (RTL), экспортируемые модулем SysUtils:

EInOutError - ошибка ввода-вывода, например, не найден файл или предпринята попытка чтения после конца файла;

EDivByZero - попытка деления на нуль при целочисленном делении;

ERangeError - значение выражения выходит за допустимые границы;

EIntOverflow - переполнение при выполнении целочисленной операции;

EZeroDivide - попытка деления на нуль в арифметике с плавающей запятой;

EOverflow - переполнение при выполнении операции с плавающей запятой;

EConvertError - ошибка преобразования числа в строку или строки в число;

EBreackPoint - приложение сгенерировало прерывание по достижению контрольной точки.

2 Современные технологии программирования

2.1 Характеристика современного этапа практики программирования

Язык Object Pascal, как один из современных языков программирования, отражает специфику и проблематику текущего этапа развития программирования. Здесь следует выделить по крайней мере три момента [3].

1). Возникло такое сравнительно новое понятие, как «программный продукт» или «программное изделие». Программа, изготовленная в одном коллективе или одним человеком, отчуждается от него и передаётся (продаётся) для использования во вне.

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

Пример. Требуется ответить на вопрос, все ли элементы массива А меньше элементов массива В? Возможный фрагмент программы

R:=0;

for i:= 1 to N do

for j:= 1 to N do

if A[i] > B[j] then R:=1;

if R=0 then write (‘Yes’) else write (‘No’);

демонстрирует неэффективность работы, так как при первом выполнении проверяемого условия дальнейшее выполнение операторов цикла можно было прервать.

2). Имеет место значительное увеличение сложности задач, решаемых с помощью ЭВМ. Это порождает дополнительные трудности при разработке и составлении программы, а также при её отладке.

3) Существенно увеличивается продолжительность «жизненного цикла» программы, т. е. того времени, в течение которого программа разрабатывается, создаётся и используется. С течением времени изменяются условия, в которых используются эти программы, а это требует регулярной модификации с целью приспособления к изменившимся условиям, изменения первоначально запланированных возможностей программ, повышения их эффективности, удобства пользования ими и т. д.

Итак, в последнее время существенно повысились требования к надёжности программ при росте их размеров и сложности, а также к удобствам их последующего сопровождения. Эта ситуация породила ряд новых проблем и трудностей. Для их преодоления практика программирования выработала ряд методов и приёмов, в том числе и таких, которые можно охарактеризовать термином «структуризация».

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

В связи с этим Паскаль предусматривает ряд мер организационного, «структурного» характера для того, чтобы представить транслятору возможность проконтролировать корректность использования в программе тех или иных программных объектов.

Например, несмотря на разнообразие допустимых типов данных, в языке последовательно выдержано требование о том, чтобы тип любой константы однозначно определялся по её записи. Эту же цель преследует и требование, чтобы каждый программный объект, в том числе и каждая переменная, был предварительно чётко описан. В частности, чтобы каждой используемой переменной был предписан вполне определённый тип. По этой же причине в Паскале предусмотрены меры, исключающие возможность выработки неоднозначно получаемого результата. Так, если i – целочисленная переменная, то недопустим оператор присваивания

i := A,

где А – вещественное. Неоднозначность заключается в том, что при А = 2.5 переменная i может получить либо значение 2. либо значение 3.в зависимости от точности вычисления значения А. Это может привести к совершенно разным окончательным результатам.

Поэтому Паскаль требует, чтобы подобного рода преобразования были заданы в программе в явном виде, для чего в языке предусмотрены специальные стандартные функции.

Для того, чтобы легче было использовать подобную информацию не только транслятору и автору программы, но и другим лицам, Паскаль требует четкой структуризации программы. Та или иная информация должна находиться в строго определённом для неё месте.

Важное значение имеет и структуризация данных. Поскольку программа задаёт правила обработки данных, то проектирование самих данных при изготовлении программы имеет не менее важное значение, чем проектирование правил их обработки.

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

Одна из трудностей изготовления надёжной программы состоит в том, что не существует какого либо формального аппарата для получения нужного алгоритма. Для любой задачи часто существует много алгоритмов её решения, каждый из которых и свой достоинства, и свои недостатки. Поэтому разработка алгоритма и программы в значительной мере ведётся методом «проб и ошибок». Полученный из тех или иных соображений вариант алгоритма подлежит проверке на его правильность и анализу на его эффективность. Это составляет серьёзную проблему.

Для уменьшения возникающих здесь трудностей в последние годы всё более широкое признание и практическое применение получают идеи структурного программирования.

Эти идеи появились из сознания того факта, что «программы пишутся для людей – на машине они только обрабатываются». Смысл сформулированного положения состоит в том, что обработка программы на машине, т. е. её трансляция и выполнение, трудностей практически не вызывает. Работу же поп проверке правильности программы, внесению в неё различного рода исправлений и изменений приходится выполнять человеку. Поэтому программа должна быть составлена и написана так, чтобы максимально облегчить и упростить эту работу. Поэтому суть концепции структурного программирования Г. Майерс например, формулирует следующим образом: «Я предпочитаю определять структурное программирование как программирование, ориентированное на общение с людьми, а не с машиной».

Идеи структурного программирования базируются на наблюдении того факта, что человек гораздо легче читает и понимает какой-либо текст в том случае, если он читает фразы в порядке их следования в этом тексте. Если же по ходу чтения его будут довольно часто отсылать на фрагменты текста, находящиеся, например, на других страницах, то это резко затрудняет восприятие и понимание читаемого текста. Поэтому структурное программирование иногда называют «программированием без операторов перехода» (или «программированием без GO TO”). Речь идёт о том, чтобы не использовать операторы перехода без особой на то необходимости.

Структурное программирование является методом составления хорошо структурированных программ, удобных для их чтения и понимания человеком, прослеживания логики их работы, внесения в них исправлений и других изменений.

Получение структурированных программ, обладающих свойствами простоты их чтения и понимания, достигается за счёт того, что любую программу предлагается строить из стандартных логических структур небольшого количества типов.

В качестве основных применяются три следующие структуры.

1)  Следование

Эта структура представляет собой последовательность блоков S1, S2, …, SK, которые выполняются друг за другом, в порядке их следования в тексте программы.

2)  Ветвление

Это управляющая структура, которая в зависимости от выполнения данного условия (значения истинности логического выражения В) определяет выбор для исполнения одного из двух заданных в этой структуре блоков S1 и S2.

3)  Повторение «делать, пока»

Данная структура представляет собой цикл, в котором блок S исполняется повторно, пока заданное условие выполняется (логическое выражение В принимает значение истина); в тот момент, когда условие впервые окажется невыполненным, циклический процесс заканчивается.

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

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

Каждый из входящих в структуры линейных блоков может быть не только отдельным оператором, задающим правила переработки данных, но и любой из допустимых структур, т. е. допускается вложенность структур.

2.2 Разработка программы

К началу непосредственного написания текста должны быть чётко определены назначение программы, её исходные данные и требуемые результаты её выполнения, разработана структура программы, т. е. чётко выделены составные блоки программы, точно определено назначение каждого из них и их взаимодействие. Именно разработка алгоритма, детальное проектирование будущей программы и является сутью программирования, наиболее важным и ответственным этапом в изготовлении программы.

Часто проектирование и написание программы производится одним и тем же лицом (программистом), который, получив задачу, стремится как можно быстрее перейти к непосредственному написанию программы, не спроектировав её предварительно. Это является одним из наиболее существенных и распространенных недостатков в работе начинающих программистов. В итоге программисту приходится параллельно выполнять два совершенно разных вида работы – и разработку программы, и её кодирование (запись на алгоритмическом языке). Программа обычно оказывается неверной, а если она и даёт правильные результаты, ьо оказывается неэффективной и нелогичной, а потому неудобной для последующей работы с нею, поскольку в её основе оказывается не тщательно продуманный, а первый случайно нащупанный вариант алгоритма. Поскольку от этого реализованного в виде программы варианта алгоритма бывает трудно отойти, то на выявление и устранение ошибок и иных дефектов в программе затрачивается гораздо больше времени, труда и машинных ресурсов, чем это имело бы место при своевременной предварительной разработке проекта программы.

Трудность разработки программ состоит в отсутствии формального аппарата для выполнения этой работы. Поэтому успешность её выполнения зависят от интуиции и имеющегося опыта. До сих пор разработка алгоритма в значительной мере является искусством. Правда, длительная практика развития программирования выработала некоторую общую методику разработки программ – метод пошаговой детализации, который называют также методом разработки «сверху вниз» или «нисходящим проектированием».

Его главная идея состоит в том, чтобы решение какой-либо сложной задачи свести к решению некоторого числа более простых задач.

Применительно к программированию суть этого метода заключается в том что сначала в решаемой задаче выделяется небольшое число (3 – 5) достаточно самостоятельных, более простых задач (подзадач), а в проектируемой программе намечается соответствующее число блоков (частей программы), каждый из которых предназначен для решения одной из выделенных подзадач, определяется назначение каждой из них, порядок выполнения этих блоков и их связи между собой по обрабатываемым данным. На этом этапе важно определить лишь функциональное назначение каждого блока – что он должен делать. Вопрос в том, как будут реализовываться возложенные на блок функции, пока можно не рассматривать.

Общую схему любой программы можно представить в виде трёх последовательно выполняемых блоков:

Блок1. Задание исходных данных.

Блок 2. Решение поставленной задачи.

Блок 3. Выдача результатов.

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

При проектировании программы, особенно её блока 1, важно задуматься над тем, как должна вести себя программа в случае задания ошибочных иди некорректных исходных данных. Если такие ошибки могут привести к значительному непроизводительному расходованию машинного времени или к серьёзным последствиям из-за выдачи неправильных результатов, то следует предусмотреть программный контроль исходных данных и соответствующую реакцию на ошибки в их задании – прекращение выполнения программы, печать диагностических сообщений и т. д. Как минимум, следует предусмотреть распечатку исходных данных, чтобы знать, при каких исходных данных на самом деле выполнялась программа.

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

Если некоторые из первоначально выделенных подзадач оказываются достаточно сложными, так что алгоритмы их решения ещё не очевидны, то к каждой из них можно применить аналогичную процедуру – это будет второй шаг детализации. Этот процесс продолжается до тех пор, пока каждый из выделенных блоков программы не окажется настолько простым, что его реализация уже не вызывает трудностей.

Переходить к следующему уровню детализации имеет смысл лишь при наличии достаточной уверенности в правильности и эффективности алгоритма на данном уровне его детализации.

Пошаговая детализация как раз очень удобна с этой точки зрения. Во-первых, потому, что на каждом очередном шаге детализации приходится принимать сравнительно небольшое число решений и потому легче проверить их правильность. К тому же отсутствие большой детализации позволяет рассмотреть и оценить несколько возможных вариантов, выбрав наилучший из них. Во-вторых, поскольку детализация какого-либо блока программы производится локально, независимо от других блоков, то и проверка правильности проделанной детализации носит локальный характер. Так что программист может не думать о всём алгоритме в целом, а сосредоточить всё своё внимание на очередном блоке.

Проектирование программы, вообще говоря, не связано с тем языком, на котором будет записываться окончательный текст программы – для этого достаточно иметь лишь представление о степени требуемой детализации, определяемой этим языком. Это обстоятельство и позволяет осуществлять разделение труда по разработке программы и её кодированию. Разделение надо осуществлять даже в том случае, если эти два этапа работ выполняются одним и тем же программистом. По ходу выполнения разработки программы надо всё время как-то фиксировать результаты проделанной работы. Для указанной цели часто используются блок-схемы.

Основное достоинство блок-схем состоит в том, что они не требуют какой-то определённой детализации алгоритма и потому могут использоваться на любых этапах разработки программы. Блок-схемы обеспечивают хорошую наглядность структуры алгоритма. Недостаток блок-схем состоит в том, что при достаточно большой степени детализации они становятся громоздкими и теряют своё основное достоинство – наглядность структуры алгоритма. Кроме того, они требуют много времени на их вычерчивание, а также неудобны для публикаций.

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

Пример:

begin

if

наибольшая компонента вектора отрицательна

then

все компоненты заменить их квадратами

else

все компоненты вектора уменьшить на 0.5

end;

while

требуемая точность не достигнута

do

вычислить и учесть очередное слагаемое ряда,

с помощью которого вычисляется sin(x);

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

2.3 Оформление программ

Одним из средств, позволяющих легко выявлять вложенность управляющих структур друг в друга и тем самым облегчить ориентацию в программе, является расположение текста отдельных операторов по листу бумаги. Служебные слова, которыми начинается и заканчивается тот или иной оператор, следует записывать на одной вертикали, а все вложенные в него операторы записывают с некоторым отступом вправо. С этой целью иногда бывает удобно объединять в составной оператор и такую последовательность операторов, где по синтаксису можно обойтись и без составного оператора.

Наиболее эффективным средством облегчения понимания программы является её комментирование.

Нередко программист намеревается снабдить свою программу комментариями позднее, на последнем этапе её изготовления. Однако эти намерения обычно не реализуются. После окончания работы по составлению и отладке программы работа по комментированию кажется ему уже излишней. Тем более, что специально для этой работы времени обычно уже не находится. Бывает и так, что спустя некоторое время автор программы и сам уже забыл многие её детали.

«Некомментированная программа – это, вероятно, наихудшая ошибка, которую может сделать программист, а также свидетельство дилетантского подхода (пусть даже программист имеет длительный опыт работы); более того, это веская причина для увольнения программиста». [4].

Комментировать программы надо по ходу их разработки и написания. Для хорошего комментирования нужны определённые практические навыки, которые вырабатываются лишь с течением времени. Мало что говорящие и неудачно расположенные комментарии только загромождают текст программы и мало способствуют её пониманию.

Можно считать, что программа прокомментирована удачно, если при первом знакомстве с нею можно понять структуру программы, её суть и логику работы, только просматривая содержащиеся в ней управляющие структуры и читая комментарии, не анализируя подробно входящие в неё операторы, задающие правила обработки данных. Изучение таких операторов нужно лишь для уточнения деталей, что необходимо, например, для тщательной проверки программы.

Заголовки служат для выделения и объяснения назначения основных блоков программы. Комментарии этого типа должны отражать результаты проделанной ранее работы по пошаговой детализации алгоритма. Построчные комментарии относятся к достаточно мелким фрагментам программы (операторам, описаниям).

Обычно каждая программа снабжается ещё «вводными» комментариями, которые помещаются в начале текста программы. С их помощью задаётся общая информация о данной программе. Эта информация обычно содержит в себе следующие пункты:

1)  назначение программы,

2)  сведения об авторе программы,

3)  организация, в которой изготовлена программа,

4)  дата написания программы,

5)  используемый метод решения задачи (если таковой имеется),

6)  указания по вводу и выводу.

Могут содержаться и другие пункты:

7)  время, требуемое на выполнение программы,

8)  требуемый объём памяти,

9)  специальные указания пользователю (в случае необходимости).

2.4 Тестирование и отладка программы

Тестирование. Именно тестирование, а не отладка является центральным моментом заключительной стадии разработки программы. Цель тестирования – убедиться в том, что программа функционирует как следует, что она соответствует требованиям и что она решает реальную задачу. Цель отладки – устранить ошибки в программе. Здесь не обязательно добиваться такого же результата, как при тестировании. При отладке на любой стадии некоторые части программы могут остаться неоттестированными, поскольку рассматриваются только те ошибки, которые проявляются, а остальные так и остаются не затронутыми.

Из за большого объема этот материал размещен на нескольких страницах:
1 2 3 4 5