Rambler's Top100


Виртуальный клуб начинающих программистов на Delphi


Заводь
Мелководье
Сокровищница
Рифы
Течения
Архивный грот
Дальние земли
Жемчужница
Ловцы жемчуга
Почтовый грот
Дельфинарий
Карта бухты

Rambler's Top100


Mastak.ru - качественный хостинг на двух континентах

The List of Russian Web Servers WebList.Ru

Визуальная модель Delphi.

Delphi - это визуальная среда разработки программ. Мы об этом уже говорили. Это значит, что большую часть оформления внешнего вида вы будете делать с использованием мышки, расставляя необходимые объекты на дизайнере форм.

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

В этой лекции я постараюсь дать все необходимые базовые знания, которые в последствии мы применим на практике. Мы уже применяли часть этих знаний, осталось только понять, как это работает. :о)

Процедурное программирование.

Вы уже знакомы с историей языков программирования? Вспомните - это самые первые лекции. С развитием языков программирования развивались и технологии, используемые при написании кода.

Первые программы писались сплошным текстом. Эта была простая последовательность команд, записанная в столбец. Все это выглядело приблизительно так:

Step1
Step2
Step3


StepN.

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

Если выполнено условие, то перейти на Step1 иначе на Step3.
Step1
Step2
Step3

StepN.

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

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

Начало процедуры 1
Step1
Step2
Конец процедуры 1

Начало программы
Step1
Step2
Если выполнено условие, то выполнить код процедуры 1.
Step3
Конец программы.

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

В процедуры можно передавать различные значения, заставляя их что-то считать:

Начало процедуры 1 (Переменная 1: строка)
Step1
Step2
Конец процедуры 1

Начало программы
Step1
Step2
Если выполнено условие, то выполнить код процедуры 1.
Step3
Конец программы.

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

Сразу хочу заметить, что использование процедуры часто называют "Вызов процедуры". Это действительно так - процедура как бы вызывается.

Давайте рассмотрим пример процедуры приближенный к реальности:

Начало процедуры 1 (Переменная 1: Целое число)
Посчитать факториал числа находящегося в Переменная 1.
Вывести результат на экран.
Конец процедуры 1

Начало программы
Процедура 1 (10)
Процедура 1 (5)
Процедура 1 (8)
Конец программы.


В этом примере я условно написал процедуру, которая вычисляет факториал переданного ей значения и потом выводит результат на экран. В самой программе я просто использую эту процедуру Процедура 1 (10), передавая ей разные значения.

Вот так я получил универсальную процедуру, которая считает факториал и выводит результат на экран. Как это все работает?

Давайте рассмотрим алгоритм:

1. Начало программы.
2. Вызов процедуры Процедура 1 (10), и передача ей значения 10.
3. Процедура вычисляет факториал числа 10 и выводит результат на экран.
4. Выход из процедуры и продолжение выполнения программы.
5. Вызов процедуры Процедура 1 (5), и передача ей значения 5.
6. Процедура вычисляет факториал числа 5 и выводит результат на экран.

И так далее. Как видите, код программы очень удобный.

Но процедуры - это мелочи жизни. Более удобным стало использование функций. Функция - это та же процедура, только она умеет возвращать значение, то есть результат своего выполнения.

Начало Функции 1: Тип возвращаемого значения - целое число
Step1
Step2
Конец Функции 1

Начало программы
Step1
Step2
Если выполнено условие, то выполнить код процедуры 1.
Step3
Конец программы.

Заметьте, что после двоеточия идет описание типа возвращаемого значения.

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

Начало Функции 1 (Переменная 1: Целое число): Целое число
Посчитать факториал числа находящегося в Переменная 1.
Вернуть результат расчета.
Конец Функции 1

Начало программы
Переменная 1:=Функция 1 (10)
Переменная 2:=Функция 1 (5)
Переменная 3:= Переменная 1+Переменная 2
Вывести на экран Переменную 3
Конец программы.

В этом примере я в "переменную 1" записывается результат расчета факториала 10! (Переменная1:=Функция 1 (10)). В "переменную 2" записывается результат расчета факториала 5!. Потом я складываю значения обеих переменных и записываю результат в переменную 3. И последнее - вывод на экран переменной 3.

Объектно-ориентированное программирование.

Следующим шагом в развитии технологий программирования было появление объектно-ориентированного программирования. Здесь уже код перестал быть "плоским". Теперь уже программист оперирует не просто процедурами и функциями, а целыми объектами.
Объект - совокупность свойств и методов и событий. Что означает "совокупность"? Это значит, что объект состоит из свойств методов и событий.

Свойства - это простые переменные, которые влияют на состояние объекта. Например, ширина, высота - это свойства объекта.
Методы - это те же процедуры и функции, т.е. это то, что объект умеет делать (вычислять). Например, объект может иметь процедуру для вывода какого-то текста на экран. Эта процедура и есть метод объекта.

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

Простой объект выглядит так:

Давай рассмотрим простой объект - кнопка. Такой объект должен обладать следующим минимальным набором:

Свойства:
1. Левая позиция (Х).
2. Верхняя позиция (Y).
3. Ширина.
4. Высота.
5. Заголовок.

Методы:
1. Создать кнопку.
2. Уничтожить кнопку.
3. Нарисовать кнопку.

События:
1. Кнопка нажата.
2. Заголовок кнопки изменен.

Объект работает как единое целое свойств, методов и событий. Например, вы изменили заголовок кнопки. Объект генерирует событие "Заголовок кнопки изменен". По этому событию вызывается метод "Нарисовать кнопку". Этот метод рисует кнопку в позиции, указанной в свойствах объекта и выводит на кнопке текст, указанный в свойстве "Заголовок".

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

Метод для создания объекта называется конструктором (constructor). Метод для уничтожения объекта называется деструктором (destructor).

Процесс создания объекта называется инициализацией.

Теперь рассмотрим процесс применения нашей кнопки. Он выглядит следующим образом:

1. Создание кнопки с помощью вызова метода "Создать кнопку".
2. Изменение необходимых свойств.

Все. Наша кнопка готова к работе.

Объект - это сложный тип. Это значит, что вы можете объявлять переменные типа "объект" (как мы объявляли переменные типа число или строка) и обращаться к объекту через эту переменную.

На языке программирования это будет выглядеть немного сложнее:

1. Объявить переменную типа Кнопка.
2. В эту переменную проинициализировать объект.
3. Можно использовать объект.

Вот тут нужно собрать все, что я уже говорил об объектах в кучу и дать небольшие пояснения, чтобы мы могли двинуться дальше.
Итак, мы можем объявлять переменные типа "объект". Давайте объявим переменную Объект1 типа Кнопка. Теперь мы можем создать кнопку, для чего есть конструктор (метод для создания объекта), который выделяет новую память для объекта. Процесс инициализации объекта кнопки выглядит так: переменной Объект1 нужно присвоить результат работы конструктора объекта Кнопка. Конструктор выделит необходимую объекту память и присвоит свойствам значения по умолчанию. Результат этого действия будет присвоен переменной Объект1.

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

Давайте напишем небольшую программу на русском языке, которая опишет весь процесс создания объекта:

Начало программы.

Переменные:
Объект1 - Кнопка;

Начало кода
Объект1:= Кнопка.Создать объект
Объект1.Заголовок:='Привет'
Объект1.Уничтожить объект.
Конец кода

Доступ к свойствам и методам объектов осуществляется как ИмяПеременнойТипаОбъект.Свойсво или ИмяПеременнойТипаОбъект.Метод. Таким образом, мы изменили в вышеуказанном примере свойство заголовок (Объект1.Заголовок) присвоив ему значение 'Привет'. Точно так же мы получили доступ к конструктору (метод "Создать объект") и деструктору (метод "Уничтожить объект").

Создание объекта - обязательно. Если вы попробуете использовать следующий код, то у вас произойдет ошибка:

Начало программы.

Переменные:
Объект1 - Кнопка;

Начало кода
Объект1.Заголовок:='Привет'
Конец кода

Здесь я просто пытаюсь изменить заголовок без создания и уничтожения объекта. Это ОШИБКА!!! Переменная Объект1 ничего не хранит. Ее просто необходимо сначала проинициализировать.

Без инициализации можно использовать только простые переменные, такие как число или строка. Тут Delphi выделяет под них память автоматически, потому что размер этих переменных - фиксированный и Delphi уже на этапе компиляции знает, сколько памяти нужно отвести под переменную.

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

Объекты - очень удобная вещь. Он работает как шаблон, на основе которого создаются переменные типа объектов. Например:

Начало программы.

Переменные:
Объект1 - Кнопка;
Объект2 - Кнопка;

Начало кода
Объект1:= Кнопка.Создать объект
Объект2:= Кнопка.Создать объект

Объект1.Заголовок:='Привет'
Объект2.Заголовок:='Пока'

Объект1.Уничтожить объект.
Объект2.Уничтожить объект.
Конец кода

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

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

Компонентная модель.

Компоненты - это более совершенные объекты. Грубо говоря, компоненты - это объекты, с которыми можно работать визуально.
Когда создавалась технология объектно-ориентированного программирования (ООП), о визуальности еще никто не думал, и она существовала только в мечтах программистов. А когда фирма Borland создавала свою первую визуальную оболочку для Windows, пришлось немного доработать концепцию ООП, чтобы с объектами можно было работать визуально.

До появления шестой версии, в Delphi существовала только одна компонентная модель - VCL (Visual Component Library - визуальная библиотека компонентов). В шестой версии появилась новая библиотека CLX (Borland Component Library for Cross Platform - кросс платформенная библиотека компонентов).

VCL - библиотека компонентов разработанная только под Windows. Она очень хорошая и универсальная, но работает только под Windows.

В 2000 году фирма Borland решила создать визуальную среду разработки для Linux. В основу этой среды разработки легла Delphi и VCL. Но просто создать новую среду разработки было слишком просто и не эффективно. Было принято решение сделать новую библиотеку компонентов, с помощью которой можно было бы писать код как под Windows, так и под Linux. Это значит, что код, написанный в Delphi под Windows должен без проблем компилироваться под Linux без дополнительных изменений.

Так в 2001 году появилась новая среда разработки Kylix, которая смогла компилировать исходные тексты, написанные на Delphi для работы в операционной системе Linux. В качестве компонентной модели использовалась новая библиотека CLX. В принципе, это та же самая VCL с небольшими доработками. Даже имена объектов остались те же.

Наследственность.

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

Одно из величайших достижений в ООП - наследование. Рассмотрим пример. Вы написали объект - "гараж". Теперь вам нужно написать объект "дом". Гараж - это, грубо говоря, однокомнатный дом. Оба эти здания обладают одинаковыми свойствами - стены, пол, потолок и т.д. Поэтому желательно взять за основу гараж и доделать его до дома. Для этого вы создаете новый объект "Дом" и пишите, что он происходит от "Гаража". Ваш новый объект сразу примет все свойства гаража. Это значит, что у вас уже будут стены, пол и потолок, и остается добавить только интерьер. Теперь у вас будет уже два объекта: гараж и дом. Можно еще создать будку для собаки. Для этого снова создаем объект "Будка", который происходит от "Гаража" (можете произвести от "дома", чтобы в будке у собаки был интерьер :)). Нужно только уменьшить размер гаража, и он превратится в будку. В итоге у вас получается древовидная иерархия наследования свойств. На рисунке я показал примерную иерархию наших объектов.

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

Точно такой же метод наследования принят и в объектно-ориентированных языках. На рисунке выше, показана небольшая иерархия, взятая из Delphi. Как видно из рисунка, все объекты происходят от TObject. Это базовый объект, который реализует основные свойства и методы. От него происходит TPersistent и TThread. Это только на моем рисунке. В реальности, от TObject происходит намного больше объектов, и все они знают о его свойствах и методах и наследуют их себе.

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

Для того чтобы можно было изменить процедуру, отвечающую за открывание двери, она должна быть объявлена у гаража, как "виртуальная" (virtual). Виртуальная процедура говорит о том, что в порожденном объекте она может быть заменена.

И это еще не все. В гараже у нас стены голые, а в доме мы хотим повесить на них картины. Для реализации этого в ООП есть обалденная штука, как вызов метода предка. Рассмотрим пример:

Процедура отвечающая за создание стен у гаража.
Начало
Создать стены
Конец

Процедура отвечающая за создание стен у дома.
Начало
Вызвать объект предка.
Повесить на стены картины.
Конец

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

Идеи и пожелания с удовольствием почитаем.

Хостинг от uCoz