Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
1) Понятие жизненного цикла ПО. Виды жизненного цикла
Промышленное применение компьютеров и растущий спрос на программы поставили актуальные задачи существенного повышения производительности разработки ПО, разработки индустриальных методов планирования и проектирования программ, переноса организационно-технических, технико-экономических и социально-психологических приемов, закономерностей и методов из сферы материального производства в сферу применения компьютеров. Комплексный подход к процессам разработки, эксплуатации и сопровождения ПО, выдвинул ряд насущных проблем, решение которых исключит «узкие места» в проектировании программ, уменьшит сроки завершения работ, улучшит выбор и адаптацию существующих программ, а может быть и определит судьбу систем со встроенными ЭВМ.
В практике разработок больших программных проектов зачастую отсутствует единый подход к оцениванию затрат труда, сроков проведения работ и материальных затрат, что сдерживает повышение производительности разработки ПО, а в конечном счете – эффективное управление жизненным циклом ПО. Поскольку программа любого типа становится изделием (кроме, может быть, учебных, макетных программ), подход к ее изготовлению во многом должен быть аналогичен подходу к производству промышленной продукции, и вопросы проектирования программ становятся чрезвычайно важными. Эта идея лежит в основе книги «Инженерное проектирование программного обеспечения», которую мы использовали при написании данной курсовой работы. В этой книге под проектированием ПО понимается процесс создания проекта программного изделия.
ЖЦПО – это непрерывный процесс, который начинается с момента принятия решения о необходимости создания ПО и заканчивается в момент его полного изъятия из эксплуатации.
Существует несколько подходов при определении фаз и работ жизненного цикла программного обеспечения (ЖЦПО), шагов процесса программирования, каскадная и спиральная модели. Но все они содержат общие основополагающие компоненты: постановка задачи, проектирование решения, реализация, обслуживание.
Шаги процесса программирования по Райли
Процесс программирования включает четыре шага:
постановка задачи, т. е. получение адекватного представления о том, какую задачу должна выполнить программа;
проектирование решения уже поставленной задачи (в общем, такое решение является менее формальным, чем окончательная программа);
кодирование программы, т. е. перевод спроектированного решения в программу, которая может быть выполнена на машине;
сопровождение программы, т. е. непрекращающийся процесс устранения в программе неполадок и добавления новых возможностей.

Программирование начинается с того момента, когда пользователь, т. е. тот, кто нуждается в программе для решения задачи, излагает проблему системному аналитику. Пользователь и системный аналитик совместно определяют постановку задачи. Последняя затем передается алгоритмисту, который отвечает за проектирование решения. Решение (или алгоритм) представляет последовательность операций, выполнение которых приводит к решению задачи. Поскольку алгоритм часто не приспособлен к выполнению на машине, его следует перевести в машинную программу. Эта операция выполняется кодировщиком. За последующие изменения в программе несет ответственность сопровождающий программист. И системный аналитик, и алгоритмист, и кодировщик, и сопровождающий программист – все они являются программистами.
В случае большого программного проекта число пользователей, системных аналитиков и алгоритмистов может оказаться значительным. Кроме того, может возникнуть необходимость вернуться к предшествующим шагам в силу непредвиденных обстоятельств. Все это служит дополнительным аргументом в пользу тщательного проектирования программного обеспечения: результаты каждого шага должны быть полными, точными и понятными.
Определение ЖЦПО по Леману
В самом общем случае можно считать, что жизненный цикл программной системы состоит из трех фаз:
определения;
реализации;
обслуживания.
Итак, были рассмотрены три подхода к определению жизненного цикла ПО. Все они имеют право на существование, так как в той или иной степени отражают практику программирования. Тем более, что легко можно обнаружить общие моменты (ставится задача – определяется система – анализируются требования; сопровождение программы – обслуживание – эксплуатация и сопровождение).
Следует помнить, что хорошее программирование – это не кодирование быстро найденного решения с помощью любой подходящей методики, а тщательно инструментированная инженерная процедура, позволяющая создать полное, точное и легко понимаемое (ясное) программное обеспечение.
Типичная диаграмма жизненного цикла проекта включает в себя следующие стадии:
- анализ
- проектирование
- реализация
- поддержка
2) Общие понятия ООП. Класс, объект, свойство, метод.
При использовании технологии ООП решение задачи представляется в виде результата взаимодействия отдельных функциональных элементов некоторой системы, имитирующей процессы, происходящие в предметной области поставленной задачи.
В такой системе каждый функциональный элемент, получив в процессе решения задачи некоторое входное воздействие (сообщение), выполняет заранее определенные действия. Например, он может изменить собственное состояние, выполнить некоторые вычисления, нарисовать окно или график и в свою очередь воздействовать на другие элементы. Передавая сообщения от элемента к элементу, система выполняет необходимые действия.
Функциональные элементы системы, параметры и поведение которой определяются условием задачи, обладающие самостоятельным поведением (т. е. «умеющие» выполнять некоторые действия, зависящие от полученных сообщений и состояния элемента), получили название объектов.
Процесс представления предметной области задачи в виде совокупности объектов, обменивающихся сообщениями, называется объектной декомпозицией.
Простейший графический редактор (вариант 1). Выполним объектную декомпозицию программы, которая по запросу пользователя рисует одну из двух фигур: квадрат или круг. При желании пользователь должен иметь возможность изменить цвет контура, размер фигуры и координаты ее центра.
По правилам выполнения объектной декомпозиции разрабатываем имитационную модель системы. Для этого придется проанализировать все происходящие в имитируемой системе процессы и выделить элементы, обладающие собственным поведением, воздействующие на другие элементы и/или являющиеся объектами такого воздействия.
Основной процесс системы - управление рисованием фигур, указанных пользователем. Все команды пользователя должны интерпретироваться, и в результате интерпретации должны формироваться команды на рисование или изменение параметров фигур. Эти процессы можно моделировать, используя три объекта: Монитор (блок управления, который получает и интерпретирует команды пользователя) и два объекта - фигуры (рис. 1.4), каждый со своими параметрами.
Диаграмма объектов графического редактора
Фигуры получают следующие сообщения: «Нарисовать», «Изменить цвет контура», «Изменить размер», «Изменить координаты». Все эти сообщения инициируются Монитором в соответствии с командой пользователя. Получив от пользователя команду «Завершить», Монитор прекращает выполнение программы.
На первый взгляд объектный подход по сравнению с процедурным кажется искусственным, особенно тем программистам, которые имеют большой опыт программирования с использованием процедурного и структурного подходов, но те преимущества, которые мы при этом получаем, безусловно, окупают затраченные усилия.
Классы. Для представления абстракций объектов используется специальный определяемый программистом тип данных - класс.
Класс - это структурный тип данных, который включает описание полей данных, а также процедур и функций, работающих с этими полями данных.
Применительно к классам такие процедуры и функции получили название методов.
Реализация объединения данных с определенными видами их обработки делает классы пригодными для описания состояния и поведения моделей реальных объектов. Совокупность полей класса определяется множеством аспектов состояния объекта с точки зрения решаемой задачи, а совокупность методов - множеством аспектов поведения объекта (рис. 14).
В программах используются переменные типа класса. Такие переменные принято называть объектами.
Соответствие объекта-абстракции классу и объектам-переменным
Описание класса (класс Окно). Пусть необходимо разработать класс, переменные которого используются для изображения на экране цветного прямоугольника заданного цвета и размера (рис. 1.15).
Проектируемый класс должен содержать поля для сохранения параметров окна: xl, yl, х2, у2 - координаты верхнего левого и нижнего правого углов и Color - цвет. Пусть единственное сообщение, обрабатываемое объектом - сообщение «Нарисовать окно». Соответственно, класс должен содержать метод, реализующий процесс рисования окна Изобразить. Поля объекта можно инициализировать при создании переменной-объекта, передав ему сообщение инициализации, включающее значения полей. Следовательно, класс должен содержать метод инициализации Инициализировать.
Окончательно получаем класс, имеющий следующую структуру:
Класс Окно:
поля XI, Y1,X2, Y2, Color
метод Инициализировать (аХ1,аY1,aX2,aY2,aColor)
метод Изобразить
Конец описания.
Создавая объекты типа Окно, инициализируя их в соответствии с условием и посылая им сообщение «Нарисовать окно», получим разные окна на экране, причем параметры этих окон будут храниться в объектах.
Каждая переменная-объект включает набор полей, объявленных в классе. Совокупность значений, содержащихся в этих полях, моделирует конкретное состояние объекта предметной области. Изменение этих значений в процессе работы отражает изменение состояния моделируемого объекта.
Воздействие на объект выполняется посредством изменения его полей или вызова его методов. Доступ к полям и методам объекта осуществляется, за исключением специальных случаев, с указанием имени объекта (при этом используют составные имена):
<имя объекта>.<имя поля> или <имя объекта>.<имя метода>
Все методы объекта обязательно имеют доступ ко всем полям своего объекта. В рассматриваемых далее языках программирования это достигается через неявную передачу в метод специального параметра - ссылки или адреса области данных конкретного объекта (ссылка Self- в Паскале и адрес this - в C++). Таким образом, уменьшается количество параметров, явно передаваемых в метод.
Ограничение доступа. Большинство версий объектно-ориентированных языков позволяет ограничить доступ к некоторым полям и методам объекта, обеспечивающим функционирование «внутренностей» объекта. При наличии таких возможностей специальными средствами выделяют интерфейс и реализацию класса. Описание класса без учета синтаксиса конкретного языка выглядит следующим образом:
Класс <имя класса>
интерфейс
<объявление полей и методов класса, к которым возможно обращение извне>
реализация
<о6ъявление полей и методов класса, к которым невозможно обращение извне>
Конец описания.
Для формального описания качества свойства, мы должны ввести его обозначение. Каждый объект может быть охарактеризован его свойствами. Каждое из них имеет значение конкретного типа.
Некоторые свойства объекта могут никогда не изменять своего значения. Когда свойство объекта меняет значение, мы говорим, что объект меняет свое состояние.
Если и свойства, и их значения двух объектов одинаковы, то эти объекты неразличимы.
Так же, как каждое значение принадлежит к конкретному типу, каждый объект принадлежит к конкретному классу, который группирует схожие объекты. Класс – это абстрактное обозначение, на самом деле он не существует. Классы описывают свойства, которые должны иметь принадлежащие к ним объекты.
Объекты одного и того же класса имеют одинаковые свойства. Когда объект принадлежит конкретному классу, мы говорим, что объект – экземпляр этого класса. Для создания объекта необходимо точно определить класс и заполнить все свойства объекта, описанные в классе, значениями.
Объекты могут действовать, изменяя свое состояние или побуждая другие объекты к действию. Действия, совершаемые объектом, формализуются методом (функцией). Функции определяются для классов так же, как свойства, хотя они одинаковы для каждого объекта класса.
Объекты могут изменять свое состояние и влиять на другие объекты, вызывая их функции. Этот процесс можно рассматривать так: один объект отправляет сообщение другому, который его принимает и действует соответствующим образом.
3) Методология ОМТ
Реальный объект – это специфическая сущность, которую мы можем видеть, чувствовать или воспринимать любым другим образом и отличать от других объектов.
Моделируя реальный мир с помощью компьютерной программы, мы приходим к понятию компьютерного объекта (или просто объекта). Объект – это специфическая компьютерная сущность, которая существует в компьютерной памяти и может описывать реальный объект.
Моделирование – процесс создания модели чего-то; означает выделение важных значащих свойств, характеристик и отбрасывание всех неважных. Это отбрасывание называется абстрагированием.
Процесс моделирования реальной ситуации с коллекцией взаимодействующих объектов называется объектной декомпозицией. Он состоит из нескольких стадий.
Первая стадия заключается в идентификации кандидатов для объектов. Это – типичные обозначения, используемые людьми при описании реальных объектов. Сущность достойна быть моделью как объект, если она более или менее выделяется и имеет уникальную структуру и поведение. Это может быть:
физический объект (дом, ручка, книга);
характеристика (форма буквы, форма фигуры);
местоположение (улица);
абстрактное обозначение (животное, графическая фигура);
событие (встреча, ЧП);
сложная сущность, состоящая из других сущностей (очередь людей, список книг, матрица целых чисел).
Каждая сущность моделируется с помощью отдельного класса.
На второй стадии отмечаются свойства, которые описывают объекты.
На третьем этапе описываются отдельные действия, которые могут совершать объекты. Эти действия моделируются с помощью функций объекта.
На четвертой стадии определяется реализация каждого объекта
Как известно, проектирование прикладной программной системы начинается с анализа требований, которым она должна будет удовлетворять. Такой анализ проводится с целью понять назначение и условия эксплуатации системы настолько, чтобы суметь составить ее предварительный проект.
При объектно-ориентированном подходе анализ требований к системе сводится к разработке моделей этой системы. Моделью системы (или какого-либо другого объекта или явления) мы называем формальное описание системы, в котором выделены основные объекты, составляющие систему, и отношения между этими объектами. Построение моделей - широко распространенный способ изучения сложных объектов и явлений. В модели опущены многочисленные детали, усложняющие понимание. Моделирование широко распространено и в науке, и в технике.
Модели помогают:
проверить работоспособность разрабатываемой системы на ранних этапах ее разработки;
общаться с заказчиком системы, уточняя его требования к системе;
вносить (в случае необходимости) изменения в проект системы (как в начале ее проектирования, так и на других фазах ее жизненного цикла).
В настоящее время существует несколько технологий объектно-ориентированной разработки прикладных программных систем, в основе которых лежит построение и интерпретация на компьютере моделей этих систем. Мы подробно ознакомимся с одной из таких технологий - OMT (Object Modeling Techniques). Эта технология оказала большое влияние на других разработчиков объектно-ориентированных технологий, а книга, в которой она описана, является одной из наиболее часто цитируемых книг по данному направлению. Более того, система обозначений (графический язык) для описания моделей, предложенная в этой книге, широко применяется в других технологиях и в статьях по объектно-ориентированной разработке программных систем.
В технологии OMT проектируемая программная система представляется в виде трех взаимосвязанных моделей:
объектной модели, которая представляет статические, структурные аспекты системы, в основном связанные с данными;
динамической модели, которая описывает работу отдельных частей системы;
функциональной модели, в которой рассматривается взаимодействие отдельных частей системы (как по данным, так и по управлению) в процессе ее работы.
Эти три вида моделей позволяют получить три взаимно-ортогональных представления системы в одной системе обозначений. Совокупность моделей системы может быть проинтерпретирована на компьютере (с помощью инструментального программного обеспечения), что позволяет продемонстрировать заказчику характер работы с будущей системой и существенно упрощает согласование предварительного проекта системы.
Модели, разработанные и отлаженные на первой фазе жизненного цикла системы, продолжают использоваться на всех последующих его фазах, облегчая программирование системы, ее отладку и тестирование, сопровождение и дальнейшую модификацию.
Как будет показано в дальнейшем, модели системы не связаны с языком программирования, на котором будет реализована система.
4) ОО-проектирование с использованием CRC-карт.
CRC-карточки. CRC обозначает Class-Responsibilities-Collaborators (Класс/Ответственности/Участники). Это простой и замечательно эффективный способ анализа сценариев. Карты CRC впервые предложили Бек и Каннингхэм для обучения объектно-ориентированному программированию, но такие карточки оказались отличным инструментом для мозговых атак и общения разработчиков между собой.
Собственно, это обычные библиографические карточки 3х5 дюйма (если позволяет бюджет вашего проекта, купите 5х7; очень хорошо, если карточки будут линованными, а разноцветные - просто мечта). На карточках вы пишите (обязательно карандашом) сверху - название класса, снизу в левой половине - за что он отвечает, а в правой половине - с кем он сотрудничает. Проходя по сценарию, заводите по карточке на каждый обнаруженный класс и дописывайте в нее новые пункты. При этом каждый раз обдумывайте, что из этого получается, и "выделяйте излишек ответственности" в новый класс или, что случается чаще всего, перенесите ответственности с одного большого класса на несколько более детальных классов, или, возможно, передайте часть обязанностей другому классу.
Карточки можно раскладывать так, чтобы представить формы сотрудничества объектов. С точки зрения динамики сценария, их расположение может показать поток сообщений между объектами, с точки зрения статики они представляют иерархии классов.
5)Событийно-управляемое программирование. Понятие события и его обработчика. Очередь событий.
События и обработчики событий.
Вызов метода может быть рассмотрен как отправка сообщения объекту, но последний вариант более шире и может моделировать реальные ситуации лучше. Объект который отправляет сообщение может не знать может ли вообще получатель обработать его или нет. В отдельных случаях от получателя требуется рассматривать сообщения и отвечать на них. Вызов метода, однако, требует, чтобы отправитель знал точно все методы объекта получателя.
Событие - это действие или инцидент, обнаруженный программой. Большинство современных приложений считаются событийно-управляемыми, потому что они проектируются так, чтобы реагировать на события. Даже программист не может предсказать точную последовательность действий.
Создатель события и отправитель ->
Среда ->
Событие ->
Диспетчер другого объекта ->
Обработчик события объекта.
Событие – это механизм, который связывает случай с каким-либо потоком.
1. Чисто-событийный подход (чистое Win32 программирование)
2. Процедурно-событийный подход (CBuilder, Delphi)
Основное отличие второго метода – в том, что событие – это указатель на метод, указывающий на метод определенного экземпляра класса. Событие – это связь между случаем и системой, такая как между действием пользователя и частью кода, отвечающим на это действие. Отвечающий код – это обработчик событий, и почти всегда он пишется разработчиком приложения. События позволяют разработчикам приложений устанавливать поведение объектов без необходимости изменять сами классы. Это известно как делегирование.
Один из ключей к традиционному программированию для Windows – это обработка сообщений, отправляемых Windows'ом приложениям. Сообщение Windows – это запись данных, которая содержит несколько полей. Наиболее важное из них – это целое значение, идентифицирующее сообщение. Другая полезная информация приходит в двух полях-параметрах. Каждый объект приложения, который проектируется для получения сообщений, объявляет Windows'у обработчик событий, или так называемую оконную процедуру. Эта оконная процедура – это метод, который обрабатывает сообщения для окна. Когда приложение создает окно, оно регистрирует оконную процедуру в ядре.
Традиционно оконная процедура содержит огромное количество операторов выбора с записями для каждого сообщения, которое должно обрабатывать окно.
Виды событий, которые могут произойти, могут быть разделены на две главные категории: пользовательские события и системные события. Пользовательские события – действия, производимые пользователем. Эти события всегда связаны с действиями пользователя. Системные события – события, которые ОС совершает для вас.
6) Наследование. Предки и потомки. Правила присваивания экземпляров для предков и потомков. Переопределение методов в потомках.
ООП характеризуется наследованием.. Наследование означает, что объекты получают функциональность от других объектов (называемых предками). Объекты могут изменять наследованное поведение. Порождённые объекты наследуют все свойства и методы от объектов от которых они порождены. Порождённый объект называется потомком и объект от которого он производится называется предком.
Потомки имеют те же свойства и методы что и объекты от которых они произведены. Потомки могут определять новые свойства и методы а также переопределять свойства и методы основного класса.
Иерархия классов - это коллекция классов с их зависимостями типа “предок - потомок”.
При написании сложных приложений часто возникает ситуация, когда класс должен комбинировать функциональность двух или более различных классов. Это может быть решено вставкой двух объектов в объект-контейнер.
Другим решением будет объявление потомка от двух классов. Это называется множественным наследованием. При множественном наследовании потомок наследует все методы и свойства всех своих предков.
Наследование. Наследование - отношение между классами, обеспечивающее возможность конструирования новых более сложных классов из уже имеющихся посредством добавления полей и определения новых методов. Реализацию этой возможности обеспечивает совокупность специальных средств языка программирования - механизм наследования. Этот же механизм позволяет классу-потомку использовать («наследовать») поля и методы одного или нескольких родительских классов.
Исходный класс, на базе которого выполняется конструирование, часто называют родителем, а производный - потомком. Если непосредственный родитель единственный, то наследование называется простым, а если таких классов несколько - то множественным (рис. 1.17). При этом класс или классы-родители и класс-потомок образуют иерархию «общее-частное».
Иерархии классов при различных видах наследования
Поскольку при наследовании каждый производный класс добавляет новые поля и/или методы, в иерархическом дереве классов по мере удаления от корня располагаются все более сложные классы, экземплярами которых будут объекты с более сложной структурой и поведением.
Наследование (класс Окно_меняющее_цвет). Построим на базе класса Окно класс-потомок, который может изменять цвет окна на экране. Для этого к родительскому классу достаточно добавить метод Изменить_цвет:
Класс Окно_меняющее_цвет -родитель: класс Окно:
метод Изменить_цвет(аCо1оr);
Конец описания.
Класс Окно_меняющее цвет содержит все поля родительского класса и все его методы. Дополнительно объекты типа Окно_меняющее_цвет могут менять цвет окна на указанный в сообщении «Изменить_цвет» (рис. 1.18).
Иерархия классов Окно и Окно_меняющее_цвет
При множественном наследовании, реализованном, например в C++, наследуются поля и методы всех родителей. В том случае, если среди родителей есть классы, принадлежащие одной иерархии, происходит дублирование полей и методов, наследуемых от общих родителей. Для того чтобы избежать неоднозначности, в C++ введено понятие виртуального наследования, при использовании которого виртуально наследуемые поля и методы не дублируются (более подробное описание и примеры см. в § 3.3).
Наследование свойств в иерархии увеличивает повторное использование кода, уменьшает размер программы и облегчает ее тестирование и отладку, существенно упрощая работу программиста. В настоящее время созданы библиотеки наиболее часто встречающихся классов, в частности интерфейсных, которые можно использовать вновь и вновь, строя на их основе классы для решения различных задач.
7) Инкапсуляция. Области видимости.
Объект или класс - это тип данных, который инкапсулирует данные и операции над данными в единый элемент. Объекты это также коллекции элементов данных. Но объекты в отличие от записей и структур содержат процедуры и функции которые оперируют над данными (они называются методами). Комбинация данных и функциональности в одном элементе называется инкапсуляция.
Таким образом, объединение в рамках одного типа – полей и методов – называется инкапсуляцией.
Класс - это структурный тип, используемый для описания некоторого множества объектов предметной области, имеющих общие свойства и поведение. Он объявляется следующим образом:
class <имя класса>{
private: <внутренние (недоступные) компоненты класса>
protected: <защищенные компоненты класса>
public: <общие (доступные) компоненты класса>
В качестве компонентов в описании класса фигурируют поля, используемые для хранения параметров объектов, и функции, описывающие правила взаимодействия с ними. В соответствии со стандартной терминологией ООП функции — компоненты класса или компонентные функции можно называть методами.
Компоненты класса, объявленные в секции private, называются внутренними. Они доступны только компонентным функциям того же класса и функциям, объявленным дружественными описываемому классу.
Компоненты класса, объявленные в секции protected, называются защищенными. Они доступны компонентным функциям не только данного класса, но и его потомков. При отсутствии наследования — интерпретируются как внутренние.
Компоненты класса, объявленные в секции public, называются общими. Они доступны за пределами класса в любом месте программы. Именно в этой секции осуществляется объявление полей и методов интерфейсной части класса.
8) Полиморфизм. Статические и динамические методы. Примеры применения.
ООП принцип – полиморфизм
Каждый объект некоторого класса в тоже время объект всех предков этого класса. Следовательно, ссылка на объект может иметь не только экземпляр класса, но также экземпляр потомка. Однако, каждая ссылка на объект на некоторый класс позволяет вызывать только методы этого класса независимо от настоящего класса объекта.
Каждый метод может быть переобъявлен в потомке. Однако, вызов метода основного класса не вызовет переобъявленный метод, несмотря на настоящий класс объекта.
Эта ситуация решается использованием полиморфных методов. Метод может быть объявлен в основном классе полиморфным и перереализован в потомке.
Если мы имеем ссылку на объект основного класса, но созданный используя конструктор потомка, тогда вызов полиморфного метода основного класса будет осуществлять метод настоящего класса.
Эта ситуация называется runtime binding. Это выполняется во всех вызывающих выражениях, не только в явных.
Полиморфные методы часто используются для объявления поведения, неизвестного в основном классе – для объявления позже в потомках.
Простой полиморфизм. При проектировании иерархии классов может обнаружиться, что некоторые элементы поведения объектов, сохраняя название, изменяются по сути. Для реализации подобных иерархий в языке программирования должен быть предусмотрен механизм, обеспечивающий возможность определения различных реализаций некоторого единого по названию метода для классов различных уровней иерархии.
Возможность изменения реализации методов в иерархии в ООП называют простым полиморфизмом, методы, имеющие одинаковое название - статическими полиморфными, а соответствующие средства языка программирования - механизмом реализации простого полиморфизма.
Совокупность статических полиморфных методов с одним именем для иерархии классов образует единый полиморфный метод иерархии, в котором реализация полиморфного метода для конкретного класса представляет отдельный аспект.
Примечание. Термин «полиморфизм» в программировании, в соответствии со своим изначальным смыслом («многообразие»), используется для обозначения встроенного механизма определения соответствия кода функции типу параметров. Такой механизм реализуется не только в средствах ООП.
Различают несколько терминов, связанных с конкретными механизмами реализации полиморфизма для различных случаев:
• чистый полиморфизм - используется для обозначения того, что один код функции может по-разному интерпретироваться в зависимости от типа аргументов; используется в языках высокого уровня абстракции, например, в языке Lisp или Smalltalk;
• перегрузка (полиморфные имена функций) - используется, когда определяется несколько функций с одним именем - одно и то же имя функции может многократно использоваться в разных местах программы; выбор нужной функции может определяться типами аргументов, областью видимости (внутри модуля, файла, класса и т. д.); если выбор определяется типом аргументов, то перегрузка называется параметрической', например, язык C++ позволяет разработчику выполнять параметрическую перегрузку функций как вне классов, так и внутри;
• переопределение - используется в ООП при необходимости задания различных реализаций одноименных методов в иерархии классов; различают:
а) простой полиморфизм - конкретный метод определяется типом объекта при компиляции программы (раннее связывание); одноименные методы при использовании простого полиморфизма называют статическими полиморфными;
б) сложный полиморфизм (полиморфные объекты) - конкретный метод определяется типом объекта при выполнении программы (позднее связывание); одноименные методы при использовании сложного полиморфизма называют виртуальными полиморфными (рассмотрены далее);
• обобщенные функции или шаблоны - используется в ООП при реализации в языке параметризованных классов (например, в C++), параметрами такого класса являются типы аргументов методов класса (рассмотрены далее).
Простой полиморфизм (класс Окно_с_текстом). Пусть необходимо разработать на базе класса Окно класс Окно_с_текстом. Для этого к полям класса Окно необходимо добавить специальные поля для определения координат первой буквы текста - Xt, Yt и поле, содержащее сам текст - Text.
Кроме того, понадобится специальный метод, который будет обрабатывать сообщение «Нарисовать». Однако у нас уже существует родительский метод Изобразить (!), который обрабатывает это сообщение. Следовательно, необходимо заменить родительский метод методом потомка. Механизм простого полиморфизма позволяет для класса-потомка Окно_с_текстом предусмотреть собственный метод Изобразить (рис. 1.19).

Иерархия классов Окно и Окно_с_текстом
Метод Инициализировать также должен быть переопределен, так как он должен инициализировать дополнительные, определенные в классе-потомке поля класса.
Класс Окно_с_текстом - родитель: класс Окно:
поля Хt, Yt, Text
метод Инициализировать (aX1,aY1,aX2,aY2,aColor, aXt, aYt, aText)
метод Изобразить
Конец описания.
Примечание. Механизм простого полиморфизма позволяет при реализации методов Изобразить и Инициализировать класса-потомка вызывать соответствующие родительские методы, а затем добавлять операторы, определяющие собственные действия метода для разрабатываемого класса.
Сложный полиморфизм или создание полиморфных объектов. Для расширения возможностей языка в Borland Pascal и C++ указателю на объект класса-родителя разрешено присваивать адрес объекта класса-потомка. Адресуемые через указатели объекты, которым в процессе выполнения программы может быть присвоено значение, тип которого отличается от типа переменной, были названы полиморфными. В рассматриваемых языках программирования подобная ситуация возникает:
• при передаче объекта класса-потомка в качестве фактического параметра подпрограмме, в которой этот параметр описан как параметр-переменная типа класса-родителя (явно - в списке параметров или неявно - в качестве внутреннего параметра self или this, используемых при вызове методов);
• при работе с динамическими объектами, когда указателю на объект класса-родителя присваивается адрес объекта класса-потомка.
Примечание. В принципе, в обоих случаях речь идет об одной и той же ситуации: во внутреннем представлении для передачи параметров-переменных используются указатели и адреса объектов.
Тип полиморфного объекта становится известным только на этапе выполнения программы. Соответственно, при вызове полиморфного метода для такого объекта нужный аспект также должен определяться на этапе выполнения. Для этого в языке должен быть реализован механизм позднего связывания, позволяющий определять тип объекта и, соответственно, аспект полиморфного метода, к которому идет обращение в программе на этапе ее выполнения.
Иерархия классов при сложном полиморфизме
Методы, для которых должно реализовываться позднее связывание, получили название динамических полиморфных или виртуальных. Для их описания в рассматриваемых далее языках программирования используется служебное слово virtual.
С помощью механизма позднего связывания реализуется оперативная перестройка программы в соответствии с типами используемых объектов.
Поясним сказанное на примере.
Пример 1.12. Сложный полиморфизм. Пусть родительский класс содержит два метода Out и Print, причем метод Out вызывает метод Print. Класс-потомок наследует метод Out, но имеет собственный метод Print (рис. 1.20).
При вызове метода Out для объекта класса-потомка необходимо обеспечить, чтобы этот метод вызывал метод Print потомка, а не родителя (рис. 1.21).
При раннем связывании определение адреса метода Print происходило бы на этапе компиляции программы, следовательно и для объекта родительского класса, и для объекта класса-потомка из метода Out вызывался бы метод Print класса-родителя. Определить, для объекта какого класса: родителя или потомка вызывается метод Out, можно только на этапе выполнения. Следовательно, для метода Print необходимо обеспечить позднее связывание.
Описание метода Print как метода, для которого запрещается определение адреса на этапе компиляции, приведет к тому, что адрес метода Print будет определяться в процессе выполнения программы. В этот момент уже будет известно, объект какого класса вызывает метод Out, и будет вызываться метод Print именно этого класса.

Необходимость позднего связывания

Реализация механизма позднего связывания
Реализация механизма позднего связывания осуществляется с использованием специальной таблицы, получившей название таблицы виртуальных методов (ТВМ). ТВМ создается для каждого класса, имеющего собственные или наследующего виртуальные методы, и содержит адреса аспектов виртуальных методов класса. Объекты же классов с виртуальными методами включают невидимое поле, содержащее адрес ТВМ своего класса (рис. 1.22). При вызове виртуального метода для объекта по этому адресу происходит обращение к ТВМ класса, по которой и определяется требуемый метод.
При использовании полиморфных объектов возникают проблемы с доступом к полям объекта, описанным в классе-потомке: указатель на объект класса-родителя связан с описанием полей класса-родителя, и поля, описанные в классе-потомке, для него «невидимы» (рис. 1.23).
В таких случаях приходится средствами используемого языка явно переопределять тип объекта.
9) Создание м уничтожение экземпляра класса. Конструкторы и деструкторы.
Конструкторы и деструкторы - это специальные методы класса. Это надо понять в первую очередь. Разумеется, эти методы обладают целым рядом особенностей (именно по этому они и выделены в специальную группу). Сейчас мы об этих особенностях и поговорим.
Первое. В отличие от других методов они должны называться особым образом. Если обычные методы могут называться как угодно, то имя констуктора должно совпадать с именем класса, а имя деструктора - с именем класса с приписанной в начале тильдой. Например, если класс называется CRect, то конструктор этого класса обязан называться тоже CRect, а деструктор - ~CRect.
Второе. В отличии от других методов конструктор и деструктор вызываются сами (а другие методы мы вызываем явным образом). Конструктор вызывается в момент создания экземпляра класса, а деструктор - в момент уничтожения. Т. е. их не надо вызывать явным образом - они вызываются сами. Именно поэтому конструкторы обычно используются для задания некоторых начальных значений для переменных класса, а деструкторы - для освобождения памяти (в случае если у вас есть внутри класса переменные-указатели).
Третье. Ни конструктор, ни деструктор не возвращают никакого значения (даже типа void). Это означает, в частности, что при обяъвлении конструтора и деструктора в классе мы перед ними не пишем ни какой тип.
Четвертое. В классе может быть несколько конструкторов (и они должны различаться параметрами), и только один деструктор (у него параметров вообще быть не может).
Особой разновидностью методов являются конструкторы и деструкторы. Напомним, что конструкторы создают, а деструкторы разрушают объекты. Создание объекта включает выделение памяти под экземпляр и инициализацию его полей, а разрушение — очистку полей и освобождение памяти. Действия по инициализации и очистке полей специфичны для каждого конкретного класса объектов. По этой причине язык Delphi позволяет переопределить стандартный конструктор Create и стандартный деструктор Destroy для выполнения любых полезных действий. Можно даже определить несколько конструкторов и деструкторов (имена им назначает сам программист), чтобы обеспечить различные процедуры создания и разрушения объектов.
Объявление конструкторов и деструкторов похоже на объявление обычных методов с той лишь разницей, что вместо зарезервированных слов function и procedure используются слова constructor и destructor. Для нашего класса TDelimitedReader потребуется конструктор, которому в качестве параметра будет передаваться имя обрабатываемого файла и разделитель элементов:
type
TDelimitedReader = class
...
// Конструкторы и деструкторы
constructor Create(const FileName: string; const ADelimiter: Char = ';');
destructor Destroy; override;
...
end;
Приведем их возможную реализацию:
constructor TDelimitedReader. Create(const FileName: string;
const ADelimiter: Char = ';');
begin
AssignFile(FileVar, FileName);
Delimiter := ADelimiter;
end;
destructor TDelimitedReader. Destroy;
begin
// Пока ничего не делаем
end;
Если объект содержит встроенные объекты или другие динамические данные, то конструктор — это как раз то место, где их нужно создавать.
Конструктор применяется к классу или к объекту. Если он применяется к классу,
Reader := TDelimitedReader. Create('MyData. del', ';');
то выполняется следующая последовательность действий:
в динамической памяти выделяется место для нового объекта;
выделенная память заполняется нулями. В результате все числовые поля и поля порядкового типа приобретают нулевые значения, строковые поля становятся пустыми, а поля, содержащие указатели и объекты получают значение nil;
затем выполняются заданные программистом действия конструктора;
ссылка на созданный объект возвращается в качестве значения конструктора. Тип возвращаемого значения совпадает с типом класса, использованного при вызове (в нашем примере это тип TDelimitedReader).
Если конструктор применяется к объекту,
Reader. Create('MyData. del', ';');
то конструктор выполняется как обычный метод. Другими словами, новый объект не создается, а происходит повторная инициализация полей существующего объекта. В этом случае конструктор не возвращает никакого значения. Далеко не все объекты корректно себя ведут при повторной инициализации, поскольку программисты редко закладывают такую возможность в свои классы. Поэтому на практике повторная инициализация применяется крайне редко.
Деструктор уничтожает объект, к которому применяется:
Reader. Destroy;
В результате:
выполняется заданный программистом код завершения;
освобождается занимаемая объектом динамическая память.
В теле деструктора обычно должны уничтожаться встроенные объекты и динамические данные, как правило, созданные конструктором.
Как и обычные методы, деструктор может иметь параметры, но эта возможность используется редко.
10) Определение свойств (Property). Методы для чтения и записи.
Поля, свойства и методы
Поля класса являются переменными, объявленными внутри класса. Они предназначены для хранения данных во время работы экземпляра класса (объекта). Ограничений на тип полей в классе не предусмотрено. В описании класса поля должны предшествовать методам и свойствам. Обычно поля используются для обеспечения выполнения операций внутри класса.
Примечание
При объявлении имен полей принято к названию добавлять заглавную букву F. Например FSomeField.
Итак, поля предназначены для использования внутри класса. Однако класс должен каким-либо образом взаимодействовать с другими классами или программными элементами приложения. В подавляющем большинстве случаев класс должен выполнить с некоторыми данными определенные действия и представить результат.
Для получения и передачи данных в классе применяются свойства. Для объявления свойств в классе используется зарезервированное слово property.
Свойства представляют собой атрибуты, которые составляют индивидуальность объекта и помогают описать его. Например, обычная кнопка в окне приложения обладает такими свойствами, как цвет, размеры, положение. Для экземпляра класса "кнопка" значения этих атрибутов задаются при помощи свойств — специальных переменных, определяемых ключевым словом property. Цвет может задаваться свойством Color, размеры — свойствами Width и Height и т. д.
Так как свойство обеспечивает обмен данными с внешней средой, то для доступа к его значению используются специальные методы класса. Поэтому обычно свойство определяется тремя элементами: полем и двумя методами, которые осуществляют его чтение/запись:
type
TAnObject = class(TObject)
function GetColor: TSomeType;
procedure SetColor(ANewValue: TSomeType);
property AColor: TSomeType read GetColor write SetColor;
end;
В данном примере доступ к значению свойства AColor осуществляется через вызовы методов GetColor и SetColor. Однако в обращении к этим методам в явном виде нет необходимости: достаточно написать:
AnObject. AColor := AValue;
AVariable := AnObject. AColor;
и компилятор самостоятельно оттранслирует обращение к свойству AColor в вызовы методов Getcolor или Setcolor. Tо есть внешне свойство выглядит в точности как обычное поле, но за всяким обращением к нему могут стоять нужные вам действия. Например, если у вас есть объект, представляющий собой квадрат на экране, и его свойству "цвет" вы присваиваете значение "белый", то произойдет немедленная перерисовка, приводящая реальный цвет на экране в соответствие со значением свойства. Выполнение этой операции осуществляется методом, который связан с установкой значения свойства "цвет".
В методах, входящих в состав свойств, может осуществляться проверка устанавливаемой величины на попадание в допустимый диапазон значений и вызов других процедур, зависящих от вносимых изменений. Если же потребности в специальных процедурах чтения и/или записи нет, можно вместо имен методов применять имена полей. Рассмотрим следующую конструкцию:
TPropObject = class(TObject)
FValue: TSomeType;
procedure DoSomething;
function Correct(AValue: Integer):boolean;
procedure SetValue(NewValue: Integer);
property AValue: Integer read FValue write SetValue;
end;
...
procedure TPropObject. SetValue(NewValue: Integer);
begin
if (NewValueoFValue) and Correct(NewValue) then EValue := NewValue;
DoSomething;
end;
В этом примере чтение значения свойства AValue означает просто чтение поля rvalue. Зато при присвоении значения внутри SetValue вызывается сразу два метода.
Если свойство должно только читаться или записываться, в его описании может присутствовать соответствующий метод:
type
TAnObject = class(TObject)
property AProperty: TSomeType read GetValue;
end;
В этом примере вне объекта значение свойства можно лишь прочитать; попытка присвоить свойству AProperty значение вызовет ошибку компиляции.
Для присвоения свойству значения по умолчанию используется ключевое слово default:
property Visible: boolean read FVisible write SetVisible default True;
Это означает, что при запуске программы свойство будет установлено компилятором в True.
Свойство может быть и векторным; в этом случае оно внешне выглядит как массив:
property APoints[Index : Integer]:TPoint read GetPoint write SetPoint;
На самом деле в классе может и не быть соответствующего поля — массива. Напомним, что вся обработка обращений к внутренним структурам класса может быть замаскирована.
Для векторного свойства необходимо описать не только тип элементов массива, но также имя и тип индекса. После ключевых слов read и write в этом случае должны стоять имена методов — использование здесь полей массивов недопустимо. Метод, читающий значение векторного свойства, должен быть описан как функция, возвращающая значение того же типа, что и элементы свойства, и имеющая единственный параметр того же типа и с тем же именем, что и индекс свойства:
function GetPoint(Index:Integer):TPoint;
Аналогично, метод, помещающий значения в такое свойство, должен первым параметром иметь индекс, а вторым — переменную нужного типа (которая может быть передана как по ссылке, так и по значению):
procedure SetPoint(Index:Integer; NewPoint:TPoint);
У векторных свойств есть еще одна важная особенность. Некоторые классы в Delphi (списки т-List, наборы строк TStrings) "построены" вокруг основного векторного свойства (см. гл. 7). Основной метод такого класса дает доступ к некоторому массиву, а все остальные методы являются как бы вспомогательными. Специально для облегчения работы в этом случае векторное свойство может быть описано с ключевым словом default:
type
TMyObject = class;
property Strings[Index: Integer]: string read Get write Put; default;
end;
Если у объекта есть такое свойство, то можно его не упоминать, а ставить индекс в квадратных скобках сразу после имени объекта:
var AMyObject: TMyObject;
begin
...
AMyObject. Strings[1] := 'First'; {первый способ}
AMyObject[2] := 'Second'; (второй способ}
...
end.
Будьте внимательны, применяя зарезервированное слово default, — как мы увидели, для обычных и векторных свойств оно употребляется в разных случаях и с различным синтаксисом.
О роли свойств в Delphi красноречиво говорит следующий факт: у всех имеющихся в распоряжении программиста стандартных классов 100% полей недоступны и заменены базирующимися на них свойствами. Рекомендуем при разработке собственных классов придерживаться этого же правила.
Внимательный читатель обратил внимание, что при объяснении терминов "поле" и "свойство" мы использовали понятие метода, и наверняка понял его общий смысл. Итак, методом называется объявленная в классе функция или процедура, которая используется для работы с полями и свойствами класса. Согласно принципам ООП (см. разд. "Инкапсуляция" далее в этой главе), обращаться к свойствам класса можно только через его методы. От обычных процедур и функций методы отличаются тем, что им при вызове передается указатель на тот объект, который их вызвал. Поэтому обрабатываться будут данные именно того объекта, который вызвал метод. На некоторых особенностях использования методов мы остановимся ниже.
11) Обработка ошибок при разработке приложения. Исключения. Способы обнаружения ошибок в объектно-ориентированных приложениях (в событийном программировании).
Обработка исключений в ООП.
Объектно-ориентированные языки часто предоставляют механизм обработки ошибок устойчивым способом. Обработка исключений позволяет приложению восстановиться после ошибки, если это возможно, и завершить работу, если необходимо, без потери данных или ресурсов.
Условия ошибки могут быть указаны исключениями. Исключение возникает, когда ошибка или другое событие прерывает нормальное выполнение программы. Исключение передает управление обработчику исключений, который позволяет вам отделить нормальную логику программы от обработчика ошибки.
Исключения – это объекты. Они могут быть сгруппированы в иерархии используя наследование, и новые исключения могут быть представлены без причинения вреда существующему коду.
Исключения предоставляют красивый способ ловить ошибки во время исполнения без остановки программы и без громоздких условных операторов.
Чтобы создать объект исключения, программисту требуется вызвать конструктор класса исключений оператором raise (throw).
Блоки кода с определенными ответчиками на исключения называются защищенными блоками, потому что они могут защищать от ошибок, которые иначе могут завершить работу приложения или уничтожить данные. Когда вы объявляете защищенный блок, вы определяете конкретных ответчиков на исключения, которые могут произойти внутри этого блока. Когда ошибка происходит в этом блоке, исключение немедленно "прыгает" в ответчик, определенный вами, и затем покидает блок.
Исключение, возникшее во вложенных защищенных блоках, вначале передает контроль ближайшему обработчику исключений. Если исключение обработано внутри этого блока, выполнение продолжается с конца вложенного блока.
Если исключение осталось необработанным, выполнение переходит во вложенный обработчик исключений, и так далее.
Один подход к получению устойчивого приложения – удостовериться, что если оно занимает ресурсы, то оно также освободит их, даже если произойдет исключение.
Когда возникает ошибка, приложение вызывает исключение. Существует 2 наиболее общих модели ответа на ошибки: выполнение очищающего кода и обработка исключения. Простейший способ ответить на исключение – гарантировать, что выполнится некоторый очищающий код. Этот тип ответа не исправляет условие, которое вызвало ошибку, но позволяет вам быть уверенным, что ваше приложение не оставит свою среду в нестабильном состоянии.
Обработка исключения устраняет условия ошибки и уничтожает объект исключения, что позволяет приложению продолжить выполнение.
12) Обработка ошибок: утверждения(Assertions). Тестирование приложений в ОО-средах.
Сегодня поговорим об использовании утверждений. Утверждения (assertion) – это код (метод или макрос), с помощью которого проверяется правильность заданного условия. Обычно утверждение использует два аргумента – логическое выражение для проверки и сообщение, которое должно выводиться пользователю в случае ошибки.
Вот пример утверждения на языке Java:
assert value!= 0 : "value is equal to 0";
Утверждения не предназначены для использования в промышленных версиях программ. В основном они используются для отладки при разработке и поддержке ПО. При сборке промышленной версии программы утверждения обычно удаляют. Главная задача утверждений – выявить противоречивые допущения, некорректные значения и условия в ходе разработки программы.
Общие принципы использования утверждений
Для ожидаемых событий используйте собственные процедуры обработки ошибок. Утверждения применяйте для событий, которые никогда не должны произойти.
Обработчик ошибок в программе должен проверять некорректные входные данные из внешних источников, предусмотренные программистом, в то время, как утверждения – ошибки в самой программе.
Отработка предусмотренного обработчика – это штатная ситуация. Отработка утверждения – признак неверной работы программы и необходимости внесения изменений в её исходный код.
Не помещайте исполняемый код в утверждения.
В некоторых компиляторах есть опции отключения исполнения утверждений. А если не компилируется код утверждений, то возникает опасность неверной работы программы, в случае если исполнение этого кода влияет на дальнейшую логику программы.
Используйте утверждения для проверки предусловий и постусловий условий.
Предусловия – это набор требований, которые должны выполняться до вызова метода/создания экземпляра класса и т. п.
Постусловия – это набор требований, которые должны выполняться после отработки метода.
Утверждениями удобно документировать пред - и постусловия. Но стоит помнить, что проверке подлежат данные, которые поступают из внутреннего кода, а не из внешних источников. Для обработки некорректного внешнего ввода должны быть предусмотрены отдельные функции. Когда же корректность проверяется у параметров, поступивших от доверенного внутреннего источника, следует использовать утверждения.
13) Компонентная модель. Технология RAD. Визуальные и невизуальные компоненты.
Rapid Application Development – Быстрая разработка приложений
Rapid Application Development (RAD) – это жизненный цикл процесса проектирования, созданный для достижения более высоких скорости разработки и качества ПО, чем это возможно при традиционном подходе к проектированию.

RAD предполагает, что разработка ПО осуществляется небольшой командой разработчиков за срок порядка трех-четырех месяцев путем использования инкрементного прототипирования с применением инструментальных средств визуального моделирования и разработки. Технология RAD предусматривает активное привлечение заказчика уже на ранних стадиях – обследование организации, выработка требований к системе. Причины популярности RAD вытекают из тех преимуществ, которые обеспечивает эта технология.
Наиболее существенными из них являются:
высокая скорость разработки;
низкая стоимость;
высокое качество.
Последнее из указанных свойств подразумевает полное выполнение требований заказчика как функциональных, так и нефункциональных, с учетом их возможных изменений в период разработки системы, а также получение качественной документации, обеспечивающей удобство эксплуатации и сопровождения системы. Это означает, что дополнительные затраты на сопровождение сразу после поставки будут значительно меньше. Таким образом, полное время от начала разработки до получения приемлемого продукта при использовании этого метода значительно сокращается.
Когда применяется RAD
Применение технологии RAD целесообразно, когда:
требуется выполнение проекта в сжатые сроки (90 дней). Быстрое выполнение проекта позволяет создать систему, отвечающую требованиям сегодняшнего дня. Если система проектируется долго, то весьма высока вероятность, что за это время существенно изменятся фундаментальные положения, регламентирующие деятельность организации, то есть, система морально устареет еще до завершения ее проектирования.
нечетко определены требования к ПО. В большинстве случаев заказчик весьма приблизительно представляет себе работу будущего программного продукта и не может четко сформулировать все требования к ПО. Требования могут быть вообще не определены к началу проекта либо могут изменяться по ходу его выполнения.
проект выполняется в условиях ограниченности бюджета. Разработка ведется небольшими RAD группами в короткие сроки, что обеспечивает минимум трудозатрат и позволяет вписаться в бюджетные ограничения.
интерфейс пользователя (GUI) есть главный фактор. Нет смысла заставлять пользователя рисовать картинки. RAD технология дает возможность продемонстрировать интерфейс в прототипе, причем достаточно скоро после начала проекта.
проект большой, но поддается разделению на более мелкие функциональные компоненты. Если предполагаемая система велика, необходимо, чтобы ее можно было разбить на мелкие части, каждая из которых обладает четкой функциональностью. Они могут выпускаться последовательно или параллельно (в последнем случае привлекается несколько RAD групп).
ПО не обладает большой вычислительной сложностью.
RAD-технология не является универсальной, то есть ее применение целесообразно не всегда. Например, в проектах, где требования к программному продукту четко определены и не должны меняться, вовлечение заказчика в процесс разработки не требуется и более эффективной может быть иерархическая разработка (каскадный метод). То же касается проектов, ПО, сложность которых определяется необходимостью реализации сложных алгоритмов, а роль и объем пользовательского интерфейса невелик.

Принципы организации RAD
Принципы RAD технологии направлены на обеспечение трех основных ее преимуществ – высокой скорости разработки, низкой стоимости и высокого качества. Достигнуть высокого качества программного продукта весьма непросто и одна из главных причин возникающих трудностей заключается в том, что разработчик и заказчик видят предмет разработки (ПО) по-разному.
Главная идея RAD технологии состоит в том, чтобы как можно быстрее донести до заказчика результаты разработки, пусть и не в полном виде. Например, реализация только пользовательского интерфейса и предъявление его заказчику позволяет уже на ранней стадии разработки получить замечания по экранным и отчетным формам и внести необходимые коррективы. В этом случае значительно возрастает вероятность успеха проекта, то есть возникает уверенность в том, что конечный продукт будет делать именно то, что ожидает заказчик. Кроме того, не следует забывать и тот факт, что разница стоимости ошибки определения требований в начале проекта и в конце равна 1:200.
Основные принципы RAD можно сформулировать следующим образом:
Работа ведется группами. Типичный состав группы - руководитель, аналитик, два программиста, технический писатель. Если проект сложный, то для него может быть выделено несколько RAD-групп. Разработка проекта выполняется в условиях тесного взаимодействия между разработчиками и Заказчиком.
Разработка базируется на моделях. Моделирование позволяет оценить проект и выполнить его декомпозицию на составные части, каждая из которых может разрабатываться отдельной RAD-группой.
Итерационное прототипирование. Разработка системы и предъявление ее заказчику осуществляется в виде последовательности развиваемых прототипов. Любой из прототипов реализует определенную часть функциональности, требуемой от конечного продукта. При этом каждый последующий прототип включает всю функциональность, реализованную в предыдущем прототипе, с добавлением новой. Число прототипов определяется на основе учета разных параметров – размера проекта, анализа рисков, пожеланий заказчика и т. д. Традиционно для проектов ПО средней сложности разрабатываются три прототипа. Первый содержит весь пользовательский интерфейс с нулевой функциональностью. Он дает возможность собрать замечания заказчика и после их устранения утвердить у него экранные и отчетные формы. Второй прототип содержит реализованную на 70-80% функциональность системы, третий – полностью реализованную функциональность. Основаниями для очередной итерации являются:
Замечания заказчика. Привлечение заказчика и конечного пользователя к оценке выходных результатов прототипа с эффективной обратной связью с командой разработчиков является гарантией того, что созданная система будет делать то, что требуется заказчику. Если замечания носят характер исправлений, они учитываются в следующем прототипе, если же изменяются требования, то выполняется переоценка проекта, и корректируются сроки и стоимость проекта.
Детализация. Выполняется программирование нереализованной части системы в соответствии с составленным планом.
Анализ результатов программирования. Исправляются ошибки, повышается эффективность программного кода и т. д.
RAD группа всегда работает только над одним прототипом. Это обеспечивает единство целей, лучшую наблюдаемость и управляемость процессом разработки, что в итоге повышает качество конечного продукта. Соответственно используемые инструментальные средства должны обеспечивать групповую разработку и конфигурационное управление проектом.
Если проект сложный, то для него может быть выделено несколько RAD групп. Большие системы разбиваются на подсистемы. Каждая подсистема разрабатывается независимой группой. Ключ успеха – правильное разбиение системы на подсистемы. Команды должны использовать общие стандарты. Обязательно финальное тестирование полной системы.
Обязательное использование инструментальных средств, автоматизирующих процесс разработки, и методик их использования, следствием чего является сокращение сроков разработки и повышение качества конечного продукта.
Принципы RAD применяются не только при реализации, но и распространяются на все этапы жизненного цикла, в частности на этап обследования организации, построения требований, анализ и дизайн.
Что обеспечивает RAD технология
Технология RAD обеспечивает:
быстроту продвижения программного продукта на рынок;
интерфейс, устраивающий пользователя;
легкую адаптируемость проекта к изменяющимся требованиям;
простоту развития функциональности системы.
14) Основные компоненты для создания интерфейса. Их назначение, свойства и методы.
Интерфейс объекта, или просто интерфейс, существует во многих языках как инструмент решения той же проблемы, что и у множественного наследования. Интерфейс определяет методы, которые могут быть реализованы в классе. Интерфейсы объявляются как классы, но им не могут быть прямо приписаны значения, и они не имеют определений своих методов. Скорее, у любого класса, поддерживающего этот интерфейс, есть ответственность обеспечить реализация методов интерфейса. Указатель на интерфейс может указывать на объект класса, который реализует этот интерфейс. Однако только методы, объявленные в интерфейсе, могут быть вызваны, используя этот указатель.
Интерфейс может иметь предков и наследовать все их методы. Но интерфейс не реализует методы. Классы, поддерживающие интерфейс, должны реализовывать его методы.
15) Компоненты для доступа к данным. Принципы организации доступа к данным.
16) Паттерны проектирования. Что такое. Зачем. Общие принципы применения паттернов проектирования.
Шаблон проектирования, Паттерн (design pattern) — это многократно применяемая архитектурная конструкция, предоставляющая решение общей проблемы проектирования в рамках конкретного контекста и описывающая значимость этого решения. Паттерн не является законченным образцом проекта, который может быть прямо преобразован в код.
Это — пример решения задачи, который можно использовать в различных ситуациях.
Объектно-ориентированные шаблоны зачастую показывают отношения и взаимодействия между классами или объектами без определения того, какие конечные классы или объекты приложения будут использоваться.
Алгоритмы по своей сути также являются шаблонами, но не проектирования, а вычисления, так как решают вычислительные задачи. В отличие же от идиом, шаблоны проектирования независимы от применяемого языка программирования.
В программной инженерии шаблон проектирования – общее решение распространенных проблем программного проектирования. Шаблон проектирования – это не законченный проект, который может быть трансформирован прямо в код. Это – описание или шаблон решения проблемы, которое может быть использовано во многих ситуациях.
Объектно-ориентированные шаблоны проектирования обычно показывают отношения и взаимодействия между классами и объектами без специфики классов или объектов окончательного приложения. Алгоритмы не мыслятся как шаблоны проектирования, так как они решают вычислительные проблемы, а не проблемы проектирования.
Шаблоны проектирования могут ускорить процесс разработки путем предоставления экспериментально доказанных парадигм разработки. Шаблоны позволяют разработчикам общаться, используя хорошо известные, хорошо понимаемые имена для пограммного взаимодействия.
Паттерн проектирования – это описание задачи, которая постоянно возникает в ходе проектирования объектно-ориентированных программ, и принципов ее решения. Причем данное решение может быть использовано повторно. Смысл паттерна – предложить решение задачи в определенных условиях.
Паттерн, в общем случае, состоит из четырех элементов:
Имя – однозначное определение паттерна, говорящее о его назначении.
Задача – условия применения паттерна.
Решение – абстрактное описание решения задачи и модель решения в виде набора связанных классов.
Результат – ожидаемые последствия применения паттерна.
Классификация.
Фундаментальные шаблоны.
Создающие шаблоны.
Структурные шаблоны.
Шаблоны поведения
Создающие шаблоны имеют дело с ситуациями создания объектов, тип которых не так легко предсказать.
Структурные шаблоны описывают способ деления программы на компоненты и способ их взаимодействия.
Шаблоны поведения описывают распространенные шаблоны взаимодействия между объектами.
17) Методики разработки ПО: экстремальное программирование, TDD, рефакторинг.
Экстрема́льное программи́рование (англ. Extreme Programming, XP) — одна из гибких методологий разработки программного обеспечения. Авторы методологии — Кент Бек, Уорд Каннингем, Мартин Фаулер и другие.
Двенадцать основных приёмов экстремального программирования (по первому изданию книги Extreme programming explained) могут быть объединены в четыре группы:
Короткий цикл обратной связи (Fine scale feedback)
Разработка через тестирование (Test driven development)
Игра в планирование (Planning game)
Заказчик всегда рядом (Whole team, Onsite customer)
Парное программирование (Pair programming)
Непрерывный, а не пакетный процесс
Непрерывная интеграция (Continuous Integration)
Рефакторинг (Design Improvement, Refactor)
Частые небольшие релизы (Small Releases)
Понимание, разделяемое всеми
Простота (Simple design)
Метафора системы (System metaphor)
Коллективное владение кодом (Collective code ownership) или выбранными шаблонами проектирования (Collective patterns ownership)
Стандарт кодирования (Coding standard or Coding conventions)
Социальная защищенность программиста (Programmer welfare):
40-часовая рабочая неделя (Sustainable pace, Forty hour week)
Парное программирование
Парное программирование предполагает, что весь код создается парами программистов, работающих за одним компьютером. Один из них работает непосредственно с текстом программы, другой просматривает его работу и следит за общей картиной происходящего. При необходимости клавиатура свободно передается от одного к другому. В течение работы над проектом пары не фиксированы: рекомендуется их перемешивать, чтобы каждый программист в команде имел хорошее представление о всей системе. Таким образом, парное программирование усиливает взаимодействие внутри команды.
Коллективное владение
Коллективное владение означает, что каждый член команды несёт ответственность за весь исходный код. Таким образом, каждый вправе вносить изменения в любой участок программы. Парное программирование поддерживает эту практику: работая в разных парах, все программисты знакомятся со всеми частями кода системы. Важное преимущество коллективного владения кодом — в том, что оно ускоряет процесс разработки, поскольку при появлении ошибки её может устранить любой программист.
Давая каждому программисту право изменять код, мы получаем риск появления ошибок, вносимых программистами, которые считают что знают что делают, но не рассматривают некоторые зависимости. Хорошо определённые UNIT-тесты решают эту проблему: если не рассмотренные зависимости порождают ошибки, то следующий запуск UNIT-тестов будет неудачным.
Заказчик всегда рядом
«Заказчик» в XP — это не тот, кто оплачивает счета, а тот, кто на самом деле использует систему. XP утверждает, что заказчик должен быть всё время на связи и доступен для вопросов.
Разрабо́тка че́рез тести́рование TDD (англ. test-driven development) — техника программирования, при которой модульные тесты для программы или её фрагмента пишутся до самой программы (англ. test-first development) и, по существу, управляют её разработкой. Является одной из основных практик экстремального программирования.
Разработка в стиле TDD состоит из коротких циклов (длительностью от 2 минут, в зависимости от опыта и стиля работы программиста). Каждый цикл состоит из следующих шагов:
Из репозитория извлекается программная система, находящаяся в согласованном состоянии, когда весь набор модульных тестов выполняется успешно.
Добавляется новый тест. Он может состоять в проверке, реализует ли система некоторое новое поведение или содержит ли некоторую ошибку, о которой недавно стало известно.
Успешно выполняется весь набор тестов, кроме нового теста, который выполняется неуспешно. Этот шаг необходим для проверки самого теста — включён ли он в общую систему тестирования и правильно ли отражает новое требование к системе, которому она, естественно, еще не удовлетворяет.
Программа изменяется с тем, чтобы как можно скорее выполнялись все тесты. Нужно добавить самое простое решение, удовлетворяющее новому тесту, и одновременно с этим не испортить существующие тесты. Большая часть нежелательных побочных и отдалённых эффектов от вносимых в программу изменений отслеживается именно на этом этапе, с помощью достаточно полного набора тестов.
Весь набор тестов выполняется успешно.
Теперь, когда требуемая в этом цикле функциональность достигнута самым простым способом, программа подвергается рефакторингу для улучшения структуры и устранения избыточного, дублированного кода.
Весь набор тестов выполняется успешно.
Комплект изменений, сделанных в этом цикле в тестах и программе заносится в репозиторий, после чего программа снова находится в согласованном состоянии и содержит четко осязаемое улучшение по сравнению с предыдущим состоянием.
Этот цикл упрощенно описывается Кентом Беком в своей книге как «красный-зеленый-рефакторинг». Красный и зеленый — это цвета полоски в среде тестирования JUnit, которая показывает, все тесты сработали или нет. При этом на первом («красном») этапе необходимо добиться того, чтобы программа просто компилировалась, без срабатывания добавленного теста.
Объектный рефакторинг.
Рефакторинг обычно применяется на уровне исходного кода. Программный рефакторинг – это трансформация программы, которая улучшает проект программы, не изменяя ее поведения. Мартин Фаулер определил рефакторинг как изменение внутренней структуры программы с целью сделать ее легче для понимания и модифицирования без изменения наблюдаемого поведения. Глагол "refactor" означает переструктурирование программы путем применения серий рефакторинга без изменения поведения.
Рефакторинг часто ассоциируется с:
множеством малых изменений, применяемых повторно;
каталогом широко обсуждаемых действий;
явными единичными тестами, применяемыми до и после каждого минимального изменения;
взаимодействующим, инструментально поддерживаемым, но не автоматическим.
Основные рефакторинги.
Переименование метода.
Инкапсуляция поля (сделать public поля private полями, предоставить доступ с помощью функций).
Выделение класса (имеется класс, выполняющий работу, которая должна выполняться двумя. Создайте новый класс и перенесите соответствующие поля в него).
Инлайн класс (если класс делает немного, перенесите все его функциональные возможности в другой класс, а этот удалите).
Инлайн метод (если тело метода понятно из его имени, то перенесите тело метода в тело его вызова, а метод удалите).
Вытягивание метода (вы имеете методы с идентичными результатами в подклассах. Создайте такой метод в суперклассе, а в подклассах удалите).
Вталкивание метода (поведение суперкласса существенно только для некоторых его подклассов. Перенесите метод в эти подклассы).
Сворачивание иерархии (если суперкласс и подкласс различаются не сильно, соедините их).
Выделение метода (если вы имеете фрагмент кода, делающий две различные вещи, выделите один фрагмент в метод с именем, объясняющим цель нового метода).
Замещение массива объектом (если вы имеете массив, в котором какие-то элементы означают разные вещи, замените массив на объект, который имеет поля для каждого элемента).
Замещение условного оператора на полиморфизм (если вы имеете условный оператор, который выбирает различные варианты поведения в зависимости от типа объекта, перенесите каждое поведение в метод подкласса, а оригинальный метод сделайте абстрактным).
18) Понятие формы. Разновидности, способы использования. Модальные и немодальные формы.
В Windows основной элемент пользовательского интерфейса - форма. В Delphi каждый проект имеет по крайней мере одно окно - главное окно приложения. Все окна в Delphi основаны на объекте TForm. В данной статье мы рассмотрим основные события учавствующие в "жизни формы".
Форма
Формы имеют свои свойства, события и методы, при помощи которых Вы можете управлять видом и поведением формы. Форма, это обычный компонент Delphi, но в отличие от других, её нет на панели компонентов. Обычно форма создаётся при создании нового проекта (File | New Application). Вновь созданная форма будет главной формой приложения.
Дополнительные формы в проекте создаются через File | New Form. Так же существуют и другие способы создания форм, но здесь мы не будем рассматривать их...
Как и любой другой компонент (объект) форма имеет свои методы и реагирует на события. Давайте рассмотрим некоторые из этих событий...
Рождение
OnCreate -> OnShow -> OnActivate -> OnPaint -> OnResize -> OnPaint...
OnCreate
Событие OnCreate возникает при создании TForm и только один раз. При создании формы (у каторой свойство Visible установлено в True), события произойдут в следующем порядке: OnCreate, OnShow, OnActivate, OnPaint. В обработчике события OnCreate можно сделать какие-либо инициализационные действия, однако, любые объекты созданные в OnCreate будут уничтожены в событии OnDestroy.
OnShow
Это событие генерируется, когда форма станет видимой. OnShow вызывается сразу перед тем, как форма станет видимой. Это событие случается, если установить свойство формы Visible в True, либо при вызове методов Show или ShowModal.
OnActivate
Это событие генерируется, когда форма становится активной, тоесть когда форма получает фокус ввода. Это событие можно использовать для того, чтобы сменить элемент формы который должен получить фокус.
OnPaint, OnResize Эти события вызываются каждый раз, когда форма изначально создаётся. При этом OnPaint вызывается каждый раз, когда какому-нибудь элементу формы необходимо перерисоваться (это событие можно использовать, если необходимо при этом рисовать на форме что-то особенное).
Жизнь
Когда форма создана и все её элементы ждут своих событий, чтобы обрабатывать их, жизнь формы продолжается до тех пор, пока кто-нибудь не нажмёт крестик в верхнем правом углу формы!
Уничтожение
При уничтожении формы, события генерируются в следующем порядке:
... OnCloseQuery -> OnClose -> OnDeactivate -> OnHide -> OnDestroy
OnCloseQuery
Если мы попытаемся закрыть форму при помощи метода Close либо другим доступным способом (Alt+F4 либо через системное меню), то сгенерируется событие OnCloseQuery. Таким образом, это событие можно использовать, чтобы предотвратить закрытие формы. Обычно, событие OnCloseQuery используется для того, чтобы спросить пользователя - уверен ли он (возможно в приложении остались несохранённые данные).
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if MessageDlg('Really close this window?', mtConfirmation,
[mbOk, mbCancel], 0) = mrCancel then
CanClose := False;
end;
Обработчик события OnCloseQuery содержит переменную CanClose, которая определяет, можно ли форме закрыться. Изначальное значение этой переменной True. Однако в обработчике OnCloseQuery можно установить возвращаемое значение CloseQuery в False, чтобы прервать выполнение метода Close.
OnClose
Если OnCloseQuery вернул CanClose=True (что указывает на то, что форма должна быть закрыта), то будет будет сгенерировано событие OnClose. Событие OnClose даёт последний шанс, чтобы предотвратить закрытие формы. Обработчик OnClose имеет параметр Action со следующими четырьмя возможными значениями: caNone. Форме не разрешено закрыться. Всё равно, что мы установим CanClose в False в OnCloseQuery. caHide. Вместо закрытия, форма будет скрыта. caFree. Форма будет закрыта, и занятые ей ресурсы будут освобождены. caMinimize. Вместо закрытия, форма будет минимизирована. Это значение устанавливается поумолчанию у дочерних форм MDI.
Замечание: Когда пользователь шутдаунит Windows, то будет вызвано OnCloseQuery, а не OnClose. Если Вы не хотите, чтобы Windows завершила свою работу, то поместите свой код в обработчик события OnCloseQuery, хотя CanClose=False не сделает, того, что сделано здесь.
OnDestroy
После того, как метод OnClose будет обработан и форма будет закрыта, то будет вызвано событие OnDestroy. В OnCreate обычно делаются действия, противоположные тем, которые проделывались в OnCreate, то есть уничтожение созданных объектов и освобождение выделенной памяти.
Естевственно, что когда главная форма проекта будет закрыто, то приложение будет завершено.
Главной характерной особенностью модальной формы является то, что она приостанавливает выполнение вызвавшей ее процедуры до тех пор, пока пользователь ее не закроет. Кроме того модальная форма не позволяет пользователю переключить фокус курсором мыши на другие формы данного приложения, пока модальная форма не будет закрыта. В результате пользователь должен выполнить определенные действия, предлагаемые модальной формой, прежде чем сможет далее продолжить работу с приложением.
В качестве модальной могут выступать формы типа AboutBox, различного рода справочники и т. д. Разработчик приложения в зависимости от задач, которые должна решить форма, должен сам определить, будет она модальной или же немодальной.
Остановимся подробнее на модальной форме.
Поведение модальной формы определяется ее основным свойством ModalResult, доступным только во время выполнения. При открытии формы методом ShowModal свойство ModalResult=0. Как только в результате каких-либо определенных событий на форме свойству ModalResult будет присвоено положительное целое значение (в зависимости от версии C++ Builder) от 1 до 8 (для 5 версии) и до 10 (для 6 версии), модальная форма закроется и пользователь продолжит работу с приложением. Численные значения и константы им соответствующие можно посмотреть во встроенной справке C++ Builder.
Модальную форму можно создать и удалить в той же области действия, что гарантированно предотвратит утечку памяти. Для этого форма не должна создаваться автоматически. С этой целью необходимо удалить ее из списка AutoCreate Forms вкладки Forms диалогового окна Project --> Options. Затем из файла с расширением. cpp удаляется или комментируется строка:


