|
На главную
В этой статье, при помощи простых метафор, я попытаюсь объяснить сложные термины
и емкие понятия для начинающих программистов или просто присматривающихся.
Переменная - это "ящик" для значения
Результат работы любой программы сводится к оперированию какими-либо
данными. Если углубиться в компьютерные тонкости, память компьютера - это
последовательность ячеек, каждая из которых представляет собой числовое значение
от 0 до 255 (1 байт). Так как ячеек очень много, единственный вариант как-то
ориентироваться - это пронумеровать каждую ячейку. Так и есть - каждый байт
оперативной памяти доступен процессору посредством порядкового номера ячейки -
адреса. Любой процессор умеет работать с ячейками памяти. Для того что бы
выполнить какое-либо действие над числом, хранящимся в ячейке памяти, процессору
обязательно нужно знать адрес этой ячейки.
В то время, когда программы писались в машинных кодах, программист должен был
помнить номера всех ячеек памяти, в которые он когда-либо что-либо записывал
(имеется в виду конечно же процесс разработки конкретной программы).
Не трудно представить, насколько усложнялся процесс написания програмы, когда
возникала необходимость работать с несколькими значениями, ведь адреса ячеек
являются простыми числами, которые мало о чем могут рассказать человеку. А
человеку свойствено образное мышление. Это значит, что нам очень трудно мысленно
манипулировать "чембытонибыло", если с этими "чембытонибыло" не связано никаких
образов (или по другому - абстракций).
Возвращаясь к числам, вспомним их прямое назначение. Числа служат для
выражения какой-либо сущности в количественном отношении. Но количество само по
себе бессмыслено вне контекста. Наглядно это демонстрирует известный анекдот,
где Василий Иваныч и Петька пилотируют аэроплан
- Петька, приборы!?
- 20!
- Что 20?!
- А что приборы?
Контекст неясен, смысла в числах - ноль! Если бы каждый прибор аэроплана была
описан в руководстве, то Василий Иваныч мог бы сослаться на данные руководства,
что бы дать понять Петьке, какой конкретно прибор его интересует.
Перепишем этот анекдот при условии что Василию Иванычу известен номер страницы
"Руководства по управлению аэропланом", на которой описывается, где
конкретно в кабине находится интересующий его прибор. Так же Василий Иваныч
знает сокровенный смысл, который несут в себе показания этого прибора. Петька
держит в руках "Руководство" и готов по первому требованию снимать показания
- Петька, стр.25!?
- ... - Петька открыл стр.25
- Петька, елы-палы, быстрее!
- ... - Петька сопоставяет содержимое стр.25 с конкретным прибором
- Петька, ё-маё, щас разобьемся, быстрее давай!
- -20!
Петька в конце-концов находит вариометр, Василий Иваныч тянет штурвал на себя
и они благополучно избегают авиакатастрофы. Петьке совсем неудобно пользоваться
числами. Такой диалог малоэффективен. Гораздо удобнее так
- Петька, вариометр?!
- -20!
С появлением первых языков программировани появилась очень полезная возможность
ассоциировать с определенным адресом памяти символьное имя, которое лаконично
отражает смысл, хранимого по этому адресу значения. В отличии от адреса,
символьное имя (или попросту псевдоним адреса памяти) легко ассоциируется с
определенной сущностью. Например, какие данные ассоциируется с незамысловатым
идентификатором userName? В большинстве случаев ответом будет - имя
пользователя. Не нужно быть семи пядей во лбу, для того, то бы расшифровать
содержимое этой переменной.
Однако, имя - это не все, что характеризует переменную. Большинство языков
высокого уровня характеризуются как нетипизированные. Это означает, что в коде
программы не требуется указывать явно какого типа переменную мы создаем. При
выполнении операций переменные автоматически подгоняются под наиболее подходящий
тип. Однако, если не учитывать типы переменных, в один прекрасный момент вы
можете обнаружить что безуспешно пытаетесь сложить корову с утюгом. Результат
возможно и будет, но вряд-ли он вас удовлетворит.
32х-разрядные процессоры могут оперировать данными трех типов: байт, слово и
двойное слово. Два последних типа это ничто иное как последовательность из
нескольких байт. Для хранения слова используется два байта следующих друг за
другом, а для двойного слова - соответствено - четыре байта. Но так как у нас
минимальная единица хранения информации это байт, резонно будет предположить,
что для хранения слова потребуется две, а для двойного слова четыре ячейки
памяти.
Определение переменной в языках низкого и среднего уровней как правило
сопровождается указанием типа значения, которое может храниться в переменной.
Эти два параметра однозначно определяют расположение ячейки, и способ
использования этой ячейки. Например, программируя на языке низкого уровня, мы
определяем переменную типа БАЙТ с именем ИКС. Процессор, зная что переменная,
находящаяся по такому адресу соответствует типу
БАЙТ, при извлечении значения этой ячейки выберет такую команду, которая
извлекает байт, а не слово или двойное слово.
В общем случае, переменная - это поименованная область памяти. В зависимости от
языка программирования, объявление переменной может требовать указания типа.
Обычно, в языках высокого уровня указание типа не требуется. Одним из моментов,
когда мы можем наблюдать синтаксические различия между языками программирования
чаще всего являются способы объявления переменных.
Однако, в современном мире программирования имя и тип это еще не все, что
программист должен знать о переменной. Существуют такие понятия как
пространство имен и область действия. Представьте, что вы пишете программу, в
которой используются несколько переменных. Имена все переменных составляют
список, определяющий пространство имен.
Предположим, в процессе разработки вы допустили ошибку, и объявили две
переменные с одинаковыми именами. При попытке собрать программу компилятор
уведомит вас о такой неоднозначной ситуации (неясно было бы двойное объявление
умышленное и мы хотим использовать
одну и ту же переменную или это ошибка и мы хотим использовать эти объявления
для хранения разных значений), что было бы невозможно, если бы имена всех
переменных оставались без контроля со стороны
компилятора. Таким образом, целостность
пространства имен сваливается с плеч программиста на компилятор, что опять же,
значительно облегчает процесс разработки и отладки. В действительности,
приведенный пример не обязательно является ошибочным для всех языков
программирования. Каждый компилятор (или интерпретатор) выдвигает свои
требования к пространству имен и что в одном
языке программирования (в данном случае C и C++)
является ошибкой, в других языках может не быть таковой.
Раньше программы умещались в одном файле, но сейчас исходный код программ может
состоять из большого количества файлов. При этом абсолютно не реально запомнить
уникальные имена по всей программе. В связи с этим (и не только) было введено
понятие области действия (или области видимости) переменной. Область действия
понятие абстрактное. Этот термин применителен только по отношению к языкам
среднего и высокого уровней. Смысл в том, что бы разбить пространство имен на
несколько независимых частей. Таким образом, в одной программе смогут
безболезненно сосуществовать несколько переменных с одинаковыми именами и даже
типами.
У опытных программистов область действия ассоциируется с текущим программным
блоком, но так как мы еще не знаем, что такое программный блок, мы рассмотрим
это на другом примере. Новичкам будет более понятна концепция разделения области
действия в пределах разных файлов (такая методика используется, например, в
perl). Это значит, что переменная объявленная в одном из файлов программы будет
абсолютно не видна из других файлов программы (при условии, что мы объявим
переменную с помощью спецификатора my). Таким образом, мы можем объявить
переменную с именем Variable в нескольких файлах проекта и это не будет ошибкой.
Более подробно область действия будет рассмотрена в процессе разбора
понятия программный блок.
| Наверх |
Последнее изменение: 2006-09-07 22:36
|
Что такое тип данных
Тип данных определяет, что из себя представляет значение и позволяет узнать,
каким образом его можно(нужно) обработать. Типы подразделяются на две
категории: базовые и пользовательские.
Первая категория - это встроенные типы значений, которые известны компилятору
(или интерпретатору). Это значит, что компилятор (интерпретатор) знает каким
образом нужно обрабатывать те или иные значения и какие операции можно
выполнять с этими значениями, а какие нельзя. Набор базовых типов специфичен
для разных компиляторов. Иначе говоря, программе написанной на одном языке
доступен набор типов, который может отличаться от набора, доступной программе
написанной на другом языке. И все же, можно выделить два наиболее
часто-используемых базовых типа, характерные для подавляющего большинства языков
программирования. Это числовой и строковый типы. Кому-то может показаться, что
такое разделение излишне - ведь и число можно хранить в виде строки.
На этом этапе важно понять, что разные языки предназначены для разных уровней
разработки. Например, в языках высокого уровня (таких как perl) не имеет
значения строковые данные хранит переменная или числовые. Компилятор (или
интерпретатор) самостоятельно определяет как ему интерпретировать значение в
зависимости от контекста. Если необходимо выполнить арифметическое сложение, то
выполняется попытка преобразовать значение переменной к числовому типу. Если же
выполняется конкатенация или интерполяция строки, то любой числовой операнд
будет автоматически преобразован к строковому типу.
Для языков более низкого уровня такое разделение более характерно, так как
команды процессора работают с числами и строками по разному. А если спустится
на самый нижний уровень (то есть на уровень команд процессора, которые в
конечном итоге представляют любую программу не зависимо от языка разработки)
32х разрядных процессоров, то такое разделение просто необходимо. Необходимость
разделения этих двух типов диктуется тем, что, как я уже говорил, числовые и
строковые данные по разному хранятся в памяти. Помимо того, на уровне
ассемблера мы увидим всего три типах данных: байт, слово и двойное слово.
Последние два представляют собой типы, состоящие из нескольких экземпляров типа
байт. Слово состоит из двух, а двойное слово, соответственно, из четырех байт.
То есть, в конечном итоге, данные любого типа преобразуются к одному из этих
трех числовых типов. Теперь должно быть понятно, почему говорят, что компьютер
работает только с числами.
Методика представления символьных (или текстовых) данных в компьютере не так
проста, как может показаться на первый взгляд. Во всяком случае, работать со
строками гораздо сложнее, нежели с целыми числами. Большинство компиляторов
реализуют свои механизмы работы с символьными данными, скрывая от программиста
рутинный часто-использующийся код.
Как же хранится в памяти строковое значение? Любой текст состоит из символов и
представляет собой определенную последовательность, для которой порядок
расположения имеет первостепенное значение. Если не учитывать порядок то смысл
текста будет утерян. Каждый символ определяется числовым значением - кодом.
Теперь мы можем представить строку как последовательность чисел. Ну а с числами
мы уже разобрались.
Теперь давайте разберемся со второй категорией типов данных - пользовательскими
типами. Прилагательное "пользовательские" не совсем ясно отражает суть этой
категории типов на данном этапе рассмотрения, правильнее было бы называть эти
типы расширенными. Однако, это определение сразу же проясняется, когда мы
начинаем говорить об этих типах как о наборах, состоящих из базовых типов.
Проще всего уяснить суть на примерах. Для простоты мы будем рассматривать
программу на языке perl, в котором тип единичного значения не существенен.
Например, название улицы, номер дома и номер квартиры можно объединить в набор,
представляющий собой новый тип значения - "адрес проживания". При этом,
заметьте, что составные элементы нового типа представляют собой значения
базовых типов: одного строкового и двух числовых. Однако, компилятор (или
интерпретатор) не знает как обрабатывать новый тип "адрес проживания", он лишь
знает как его хранить (так как знает способ хранения данных базовых типов).
Программист должен реализовать механизм обработки самостоятельно.
Но не обязательно пользовательский тип данных должен представлять собой набор
базовых типов. Это может быть отдельный элемент базового типа, но при этом
механизмы обработки данных этого типа будут определяться программистом. Весь
смысл пользовательских типов данных заключается в расширении возможностей
базовых типов. Как следствие возможность расширения языка пользовательскими
типами придает языку большую гибкость.
Использование пользовательских типов данных является промежуточным этапом
на пути к исследованию методологии объектно-ориентированного программирования.
Этот этап относится к специфики модульного программирования. В качестве примера
можно привести язык С, в котором введено понятие структур - возможности описания
пользовательских типов, построенных на основе базовых. Структуры в C позволяют
не только определять наборы, но также идентифицировать наборы и манипулировать
ими на уровне единиц.
Следующим этапом эволюции в программирования было введение понятия класса
данных. Методики объектно-ориентированного подхода в программировании очень
хорошо просматриваются в языке C++. Считайте класс развитием структуры из C.
Структуры позволяли только описывать данные, в то время как класс позволяет не
только строить новые типы на основе базовых, но и определять методы обработки
нового типа данных. Такое объединение данных и методов принято называть
инкапсуляцией.
| Наверх |
Последнее изменение: 2006-09-07 19:24
|
Что такое интерфейс
Программный интерфейс, аналогичную любому другому интерфейсу, выполняет роль
связующего звена между пользователем и механизмом, обладающим определенным
функциональным потенциалом. Попросту говоря, интерфейс - это преводчик между
пользователем и механизмом. Под механизмом здесь следует понимать не какое-либо
конкретное устройство, а некую абстракцию, наделенную способностью решать
определенного рода задачи. Более того, за счет интерфейса пользователь именно
что должен воспринимать этот механизм как абстракцию.
Первым признаком плохого интерфейса является необходимость чрезмерного вникания
в детали функционирования интерфейса. И наоборот, чем меньше пользователь
отвлекается на изучение интерфейса, тем удачнее интерфейс. Хороший
интерфейс позволяет пользователю задействовать определенную функцию конечного
механизма и получить ожидаемый результат с наименьшими затратами. Плохой
интерфейс подразумевает перегрузку пользователя лишними действиями.
Однако, реакция на ввод данных это не все. Вывод данных в удобной для восприятия
пользователем форме так же является составляющей частью интерфейса. Успешным
можно назвать такой интерфейс, которые требует наименьших затрат для инициации
выполнения определенной функции и при этом предоставляет результат в
интуитивно-понятном для пользователя виде. Интуитивно-понятный вид относится
конечно же в случае, когда мы рассматриваем в качестве пользователя человека. В
контексте программирования под пользователем следует понимать несколько другой
аспект.
На самом деле, границы интерфейса различить довольно сложно. Очень трудно
сказать - вот здесь начинается интерфейс, а вот здесь он заканчивается. Начнем с
того, что интерфейс является двусоставной абстракцией. Возвращаясь к ассоциации
с переводчиком, представим, что в нашем общении с иностранным гостем нам
помогает человек, который отлично говорит на языке гостя и посредственно на нашем
родном языке. Конечно, в данном случае качество общения заметно падает, потому
что переводчик, неважно владеющий одним из языков, может неправильно
интерпретировать определенные слова, фразы или даже хуже - контекст.
Может показаться, что эта тонкость малоощутима в программировании, ведь в
большинстве случаев интерфейс является кабелем, входящим в состав
механизма-абстракции. Действительно, кабель, выходящий откуда-то из вашей мыши
в большинстве случаев воспринимается как часть устройства. Однако более
продвинутые пользователи знают, что это иллюзия и кабель это всего лишь
физическая ипостась интерфейса. На самом деле, здесь важен не кабель, а
протокол, согласно которого происходит обмен данными. Знание этого протокола
есть вершина профессионализма (в определенной области, конечно).
Но в нашем случае обратная от пользователя сторона интерфейса еще более
призрачна. В качестве примера можно рассмотреть чисто-виртуальные (pure-virtual)
методы и способы их использования, применяемые в объектно-ориентированном
программировании. Например, использование чисто-виртуальных функций может быть
обусловлено необходимостью описания интерфеса как протокола, до того как будет
реализован непосредственно функционал. Т.е. фактически, виртуальный класс
можно использовать для разработки пользователей класса еще до того, как этот
класс будет начинен функционалом.
Вот здесь начинается ощущаться разница между пользователем программы и
пользователем программного интерфейса. Пользователь программы
посредством интерфейса получает доступ к определенным функциям программы с
целью получить определенный результат. Для программиста
интерфейс играет важную роль не только на момент использования, но и на этапе
проектирования и программирования. Убедиться в этом позволит простой пример,
когда вы работаете вдвоем. Как вы будете координировать работу двух
программистов? Правильно, посредством заранее оговоренного интерфейса.
Но все-таки, что же такое программный интерфейс простыми словами? Программный
интерфейс - это набор функций в контексте модульного программирования, или набор
методов класса в контексте объектно-ориентированного программирования,
посредством которого реализуется доступ к определенной законченную
функциональности. Понятие данных по отношению к интерфейсу, рассматривается
исключительно на уровне аргументов и возвращаемых значений.
Для программного интерфеса большую важность имеет документация. Зачастую именно
от качества документации зависит КПД функциональности, доступ к которой
реализуется посредством данного программного интерфеса. Чем меньше тонкостей
затронуто в документации, тем больше потенциальных граблей, на которые будут
наступать программисты в процессе использования функциональности. Естественно,
что с увеличением количества граблей растет и количество чертыханий, которые
раздосадованные программисты направляют в адрес автора программного
решения. Так что, документируйте с избытком! :)
| Наверх |
Последнее изменение: 2005-05-27 11:16
|
|