Полезное в сети

Всегда в теме

Статистика


Яндекс.Метрика


Онлайн всего: 1
Гостей: 1
Пользователей: 0

Рекомендуем



Главная » Статьи » Образовательные » Программирование

Основы объектно-ориентированного программирования на Java
1.1. Методология процедурно-ориентированного программирования
Появление первых электронных вычислительных машин или компьютеров ознаменовало новый этап в развитии техники вычислений. Казалось, достаточно разработать последовательность элементарных действий, каждое из которых можно преобразовать в понятные компьютеру инструкции, и таким образом любая вычислительная задача будет решена. Эта идея оказалась настолько жизнеспособной, что долгое время доминировала
над всем процессом разработки программ. Появились специализированные языки
программирования, предназначенные для разработки программ, предназначенных для
решения вычислительных задач. Примерами таких языков могут служить FOCAL (FOrmula
CALculator) и FORTRAN (FORmula TRANslator).
Основой такой методологии разработки программ являлась процедурная или
алгоритмическая организация структуры программного кода. Это было настолько
естественно для решения вычислительных задач, что целесообразность такого подхода
ни у кого не вызывала сомнений. Исходным понятием этой методологии было понятие
алгоритма. Алгоритм - это способ решения вычислительных и др. задач, точно описывающий
определенную последовательность действий, которые необходимо выполнить для
достижения заданной цели или решения поставленной задачи
Примерами алгоритмов являются хорошо известные правила нахождения корней
квадратного уравнения или линейной системы уравнений.
При увеличении объемов программ для упрощения их разработки появилась необходимость
разбиения больших задач на подзадачи. В языках программирования возникло и
закрепилось новое понятие процедуры. Использование процедур позволило разбивать
большие задачи на подзадачи и таким образом упростило написание больших программ.
Кроме того, использование процедурного подхода позволило уменьшить объем
программного кода за счет написания часто используемых кусков кода в виде процедур и
использования их в различных частях программы.
Так же, как и алгоритм, процедура представляет собой законченную последовательность
действий или операций, направленных на решение отдельной задачи. В языках
программирования появилась специальная синтаксическая конструкция, которая также
получила название процедуры. Например, на языке Pascal описание процедуры выглядит
следующим образом:
Procedure printGreeting(name: String)
Begin
Print("Hello, ");
PrintLn(s);
End;
Назначение данной процедуры - вывести на экран приветствие "Hello, Name", где Name
передается в процедуру в качестве входного параметра.
Со временем вычислительные задачи становились все сложнее, а значит, и решающие
их программы увеличивались в размерах. Их разработка превратилась в серьезную
проблему. Когда программа становится все больше, ее требуется разделять на все более
мелкие фрагменты. Основой для такого разбиения как раз и стала процедурная
декомпозиция, при которой отдельные части программы, или модули, представляли собой
совокупность процедур для решения одной или нескольких задач. Одной из основных
особенностей процедурного программирования заключается в том, что оно позволило
создавать библиотеки подпрограмм (процедур), которые можно было бы использовать
повторно в различных проектах или в рамках одного проекта. При процедурном подходе
для визуального представления алгоритма выполнения программы используется так
называемая Блок-схема. Соответствующая система графических обозначений была
зафиксирована в ГОСТ 19.701-90. Пример блок-схемы изображен на рисунке (рис. 1.1).
Программирование на Java
Появление и интенсивное использование условных операторов и оператора безусловного
перехода стало предметом острых дискуссий среди специалистов по программированию.
Дело в том, что бесконтрольное применение в программе оператора безусловного перехода
goto способно серьезно осложнить понимание кода. Такие запутанные программы
сравнивали с порцией спагетти, называя их "bowl of spaghetti", имея в виду многочисленные
переходы от одного фрагмента программы к другому, или, что еще хуже, возврат от
конечных операторов программы к начальным. Ситуация казалась настолько драматичной,
что в литературе зазвучали призывы исключить оператор goto из языков программирования.
Именно с этого времени принято считать хорошим стилем отсутствие безусловных
переходов.
Дальнейшее увеличение программных систем способствовало становлению новой точки
зрения на процесс разработки программ и написания программных кодов, которая получила
название методологии структурного программирования. Ее основой является процедурная
декомпозиция предметной области решаемой задачи и организация отдельных модулей
в виде совокупности процедур. В рамках этой методологии получило развитие нисходящее
проектирование программ, или проектирование "сверху-вниз". Период наибольшей
популярности идей структурного программирования приходится на конец 70-х - начало 80-
х годов.
В этот период основным показателем сложности разработки программ считали ее размер.
Вполне серьезно обсуждались такие оценки сложности программ, как количество строк
программного кода. Правда, при этом делались некоторые предположения относительно
синтаксиса самих строк, которые должны были удовлетворять определенным правилам.
Например, каждая строка кода должна была содержать не более одного оператора. Общая
трудоемкость разработки программ оценивалась специальной единицей измерения -
"человеко-месяц" или "человеко-год". А профессионализм программиста напрямую
связывался с количеством строк программного кода, который он мог написать и отладить
в течение, скажем, месяца.
Методология процедурно-ориентированного программирования Стр. 3 из 24
Программирование на Java
Rendered by www.RenderX.com
1.2. Методология объектно-ориентированного программирования
Увеличение размеров программ приводило к необходимости привлечения большего числа
программистов, что, в свою очередь, потребовало дополнительных ресурсов для
организации их согласованной работы. В процессе разработки приложений заказчик
зачастую изменял функциональные требования, что еще более усложняло процесс создания
программного обеспечения.
Но не менее важными оказались качественные изменения, связанные со смещением
акцента использования компьютеров. В эпоху "больших машин" основными потребителями
программного обеспечения были такие крупные заказчики, как большие производственные
предприятия, финансовые компании, государственные учреждения. Стоимость таких
вычислительных устройств была слишком высока для небольших предприятий и
организаций.
Позже появились персональные компьютеры, которые имели гораздо меньшую стоимость
и были значительно компактнее. Это позволило широко использовать их в малом и среднем
бизнесе. Основными задачами в этой области являются обработка и манипулирование
данными, поэтому вычислительные и расчетно-алгоритмические задачи с появлением
персональных компьютеров отошли на второй план.
Как показала практика, традиционные методы процедурного программирования не способны
справиться ни с нарастающей сложностью программ и их разработки, ни с необходимостью
повышения их надежности. Во второй половине 80-х годов возникла настоятельная
потребность в новой методологии программирования, которая была бы способна решить
весь этот комплекс проблем. Ею стало объектно-ориентированное программирование
(ООП).
После составления технического задания, начинается этап проектирования, или дизайна,
будущей системы. Объектно-ориентированный подход к проектированию основан на
представлении предметной области задачи в виде множества моделей для языково-
независимой разработки программной системы на основе ее прагматики.
Последний термин нуждается в пояснении. Прагматика определяется целью разработки
программной системы, например обслуживание клиентов банка, управление работой
аэропорта, обслуживание чемпионата мира по футболу и т.п. В формулировке цели
участвуют предметы и понятия реального мира, имеющие отношение к создаваемой
системе (см. рисунок 1.2). При объектно-ориентированном подходе эти предметы и понятия
заменяются моделями, т.е. определенными формальными конструкциями,
представляющими их в программной системе.
Модель содержит не все признаки и свойства представляемого ею предмета или понятия,
а только те, которые существенны для разрабатываемой программной системы. Тем самым
модель "беднее", а, следовательно, проще представляемого ею предмета или понятия.
Простота модели по отношению к реальному предмету позволяет сделать ее формальной.
Благодаря такому характеру моделей при разработке можно четко выделить все
зависимости и операции над ними в создаваемой программной системе. Это упрощает
как разработку и изучение (анализ) моделей, так и их реализацию на компьютере.
Объектно-ориентированный подход помогает справиться с такими сложными проблемами,
как
• уменьшение сложности программного обеспечения;
• повышение надежности программного обеспечения;
• обеспечение возможности модификации отдельных компонентов программного
обеспечения без изменения остальных его компонентов.
• обеспечение возможности повторного использования отдельных компонентов
программного обеспечения.
Более детально преимущества и недостатки объектно-ориентированного программирования
будут рассмотрены в конце главы, так как для их понимания необходимо знание основных
понятий и положений ООП.
Систематическое применение объектно-ориентированного подхода позволяет
разрабатывать хорошо структурированные, надежные в эксплуатации, достаточно просто
модифицируемые программные системы. Этим объясняется интерес программистов к
объектно-ориентированному подходу и объектно-ориентированным языкам
программирования. ООП является одним из наиболее интенсивно развивающихся
направлений теоретического и прикладного программирования.
1.3. Объекты
По определению будем называть объектом понятие, абстракцию или любой предмет с
четко очерченными границами, имеющую смысл в контексте рассматриваемой прикладной
проблемы. Введение объектов преследует две цели:
• понимание прикладной задачи (проблемы);
• введение основы для реализации на компьютере.
Примеры объектов: форточка, Банк "Империал", Петр Сидоров, дело № 7461, сберкнижка
и т.д.
Каждый объект имеет определенное время жизни. В процессе выполнения программы
или функционирования какой-либо реальной системы могут создаваться новые объекты
и уничтожаться уже существующие.
Гради Буч дает следующее определение объекта:
Объект - это мыслимая или реальная сущность, обладающая характерным поведением,
отличительными характеристиками и являющаяся важной в предметной области.[1]
Каждый объект имеет состояние, обладает некоторым хорошо определенным поведением
и уникальной идентичностью.
1.3.1. Состояние.
Рассмотрим пример. Любой человек может находиться в некотором положении (состоянии)
стоять, сидеть, лежать, и в то же время совершать какие либо действия.
Например, человек может прыгать, если он стоит, и не может - если он лежит, для этого
ему потребуется сначала встать. Также в объектно-ориентированном программировании
состояние объекта может определяться наличием или отсутствием связей между
моделируемым объектом и другими объектами. Более подробно все возможные связи
между объектами будут рассмотрены в разделе Типы отношений между классами.
Например, если у человека есть удочка (у него есть связь с объектом Удочка), то он может
ловить рыбу, а если удочки нет, то такое действие невозможно. Из этих примеров видно,
что набор действий, которые может совершать человек, зависит от параметров объекта,
который его моделирует.
Для рассмотренных выше примеров такими характеристиками, или атрибутами, объекта
Человек являются:
• текущее положение человека (стоит, сидит, лежит);
• наличие удочки (есть или нет).
В конкретной задаче могут появиться и другие свойства, например, физическое состояние,
здоровье (больной человек обычно не прыгает).
Состояние (state) - совокупный результат поведения объекта: одно из стабильных условий,
в которых объект может существовать, охарактеризованных количественно; в любой
конкретный момент времени состояние объекта включает в себя перечень (обычно,
статический) свойств объекта и текущие значения (обычно, динамические) этих свойств.
1.3.2. Поведение
Каждый объект имеет определенный набор действий, которые с ним можно произвести.
Например, возможные действия с некоторым файлом операционной системы ПК:
• создать
• открыть
• читать из файла
• писать в файл
• закрыть
• удалить
Результат выполнения действий зависит от состояния объекта на момент совершения
действия, т.е. нельзя, например, удалить файл, если он открыт кем-либо (заблокирован).
В то же время действия могут менять внутреннее состояние объекта - при открытии или
закрытии файла свойство "открыт" принимает значения "да" или "нет" соответственно.
Программа, написанная с использованием ООП, обычно состоит из множества объектов,
и все эти объекты взаимодействуют между собой. Обычно говорят, что взаимодействие
между объектами в программе происходит посредством передачи сообщений между ними.
В терминологии объектно-ориентированного подхода понятия "действие", "сообщение" и
"метод" являются синонимами. Т.е. выражения "выполнить действие над объектом",
"вызвать метод объекта" и "послать сообщение объекту для выполнения какого-либо
действия" эквивалентны. Последняя фраза появилась из следующей модели. Программу,
построенную по технологии ООП, можно представить себе как виртуальное пространство,
заполненное объектами, которые условно "живут” некоторой жизнью. Их активность
проявляется в том, что они вызывают друг у друга методы, или посылают друг другу
сообщения. Внешний интерфейс объекта, или набор его методов, это описание, какие
сообщения он может получать.
Поведение (behavior) - действия и реакции объекта, выраженные в терминах передачи
сообщений и изменения состояния; видимая извне и воспроизводимая активность объекта.
1.3.3. Уникальность
Уникальность - это то, что отличает один объект от других. Например, у вас может быть
несколько абсолютно одинаковых монет, даже если абсолютно все их свойства (атрибуты)
одинаковы (год выпуска, номинал и.д.) и при этом вы можете использовать их независимо
друг от друга - они по-прежнему остаются разными монетами.
В машинном представлении под параметром уникальности объекта наиболее часто
понимается адрес размещения объекта в памяти.
Identity (уникальность) объекта состоит в том, что всегда возможно определить, указывают
ли две ссылки на один и тот же объект, или на разные объекты. При этом два объекта
могут во всем быть похожими, их образ в памяти может представляться одинаковыми
последовательностями байтов, но, тем не менее, их Identity может быть различна.
Наиболее распространенной ошибкой является понимание уникальности как имя ссылки
на объект. Это не верно, т.к. на один объект могут указывать несколько ссылок и ссылки
могут менять свои значения (ссылаться на другие объекты) за время своего существования.
Итак, уникальность (identity) - природа объекта; то, что отличает его от других объектов.
1.4. Классы
Все монеты из предыдущего примера принадлежат одному и тому же классу объектов
(именно с этим связана их одинаковость). Номинальная стоимость монеты, металл, из
которого она изготовлена, форма - это атрибуты класса: совокупность атрибутов и их
значений характеризует объект. Наряду с термином "атрибут" часто используют термины
"свойство" и "поле", которые в объектно-ориентированном программировании являются
синонимами.
Все объекты одного и того же класса описываются одинаковыми наборами атрибутов.
Однако объединение объектов в классы определяется не наборами атрибутов, а
семантикой. Так, например, объекты конюшня и лошадь могут иметь одинаковые атрибуты:
цена и возраст. При этом они могут относиться к одному классу, если рассматриваются в
задаче просто как товар, либо к разным классам, если в рамках поставленной задачи они
будут использоваться различными способами, т.е. над ними будут совершаться различные
действия.
Объединение объектов в классы позволяет рассмотреть задачу в более общей постановке.
Класс имеет имя (например, лошадь), которое относится ко всем объектам этого класса.
Кроме того, в классе вводятся имена атрибутов, которые определены для объектов. В
этом смысле описание класса аналогично описанию типа структуры или записи (record),
которые широко применяются в процедурном программировании; при этом каждый объект
имеет тот же смысл, что и экземпляр структуры (переменная или константа
соответствующего типа).
Формально класс - шаблон поведения объектов определенного типа с определенными
параметрами, определяющими состояние. Все экземпляры одного класса (объекты,
порожденные от одного класса)
• Имеют один и тот же набор свойств
• Общее поведение, одинаково реагируют на одинаковые сообщения
В соответствии с UML (Unified Modeling Language, унифицированный язык моделирования)
класс имеет следующее графическое представление:
Класс изображается в виде прямоугольника, состоящего из трех частей. В верхней части
помещается название класса, в средней - свойства объектов класса, в нижней - действия,
которые можно выполнять с объектами данного класса (методы).
Каждый класс может также иметь специальные методы, которые автоматически вызываются
при создании и уничтожении объектов этого класса:
• конструктор (constructor) - выполняется при создании объектов;
• деструктор (destructor) - выполняется при уничтожении объектов;
Обычно конструктор и деструктор имеют специальный синтаксис, который может отличаться
от синтаксиса, используемого для написания обычных методов класса.
1.4.1. Инкапсуляция
Инкапсуляция (encapsulation) - это сокрытие реализации класса и отделение его внутреннего
представления от внешнего (интерфейса). При использовании объектно-ориентированного
подхода не принято использовать прямой доступ к свойствам какого-либо класса из методов
других классов. Для доступа к свойствам класса принято использовать специальные методы
этого класса для получения и изменения его свойств.
Внутри объекта данные и методы могут обладать различной степенью открытости (или
доступности). Степени доступности, принятые в языке Java, подробно будут рассмотрены
в более поздних главах. Они позволяют более тонко управлять свойством инкапсуляции.
Открытые члены класса составляют внешний интерфейс объекта. Эта та функциональность,
которая доступна другим классам. Закрытыми обычно объявляются все свойства класса,
а так же вспомогательные методы, которые являются деталями реализации и от которых
не должны зависеть другие части системы.
Благодаря сокрытию реализации за внешним интерфейсом класса можно менять
внутреннюю логику отдельного класса, не меняя код остальных компонентов системы.
Обеспечение доступа к свойствам класса только через его методы также дает ряд
преимуществ. Во-первых, так гораздо проще контролировать корректные значения полей,
ведь прямое обращение к свойствам отслеживать невозможно, а значит им могут присвоить
некорректные значения.
Во-вторых, не составит труда изменить способ хранения данных. Если информация станет
храниться не в памяти, а в долговременном хранилище, таком как файловая система или
база данных, то потребуется изменить лишь ряд методов одного класса, а не вводить эту
функциональность во все части системы.
Наконец, программный код, написанный с использованием этого принципа легче отлаживать.
Для того чтобы узнать, в какой момент времени и кто изменил свойство интересующего
нас объекта, достаточно добавить вывод отладочной информации в тот метод объекта,
посредством которого осуществляется доступ к свойству этого объекта. При использовании
прямого доступа к свойствам объектов программисту бы пришлось добавлять вывод
отладочной информации во все участки кода, где используется интересующий нас объект.
1.4.2. Полиморфизм
Полиморфизм является одним из фундаментальных понятий в объектно-ориентированном
программировании наряду с наследованием и инкапсуляцией. Слово полиморфизм
греческого происхождения и означает "имеющий много форм". Чтобы понять, что означает
полиморфизм применительно к объектно-ориентированному программированию,
рассмотрим пример.
Предположим мы хотим написать векторный графический редактор, в котором опишем в
виде классов набор графических примитивов - Point, Line, Circle, Box, и т.д. У каждого из
этих классов определим метод draw для отображения соответствующего примитива на
экране.
Очевидно, придется написать некоторый код, который при необходимости отобразить
рисунок будет последовательно перебирать все примитивы, которые на момент отрисовки
находятся на экране, и вызывать метод draw у каждого из них. Человек, незнакомый с
полиморфизмом, вероятнее всего создаст несколько массивов: отдельный массив для
каждого типа примитивов и напишет код, который последовательно переберет элементы
из каждого массива и вызовет у каждого элемента метод draw. В результате получится
примерно следующий код:
//создание пустого массива, который может содержать
//объекты Point с максимальным объемом 1000
Point[] p = new Point[1000];
Line[] l = new Line[1000];
Circle[] c = new Circle[1000];
Box[] b = new Box[1000];
// предположим, в этом месте происходит заполнение всех массивов
// соответствующими объектами
for(int i = 0; i < p.length;i++){ //цикл с перебором всех ячеек массива.
//вызов метода draw() в случае,
// если ячейка не пустая.
if(p[i]!=null) p.draw();
}
for(int i = 0; i < l.length;i++){
if(l[i]!=null) l.draw();
}
for(int i = 0; i < c.length;i++){
if(c[i]!=null) c.draw();
}
for(int i = 0; i < b.length;i++){
if(b[i]!=null) b.draw();
}
Недостатком написанного выше кода является дублирование практически идентичного
кода для отображения каждого типа примитивов. Также неудобно то, что при дальнейшей
модернизации нашего графического редактора и добавлении возможности рисовать новые
типы графических примитивов, например Text, Star и т.д., при таком подходе придется
менять уже существующий код и добавлять в него определения новых массивов, а также
обработку элементов, содержащихся в них.
Используя полиморфизм, мы можем значительно упростить реализацию подобной
функциональности. Прежде всего, создадим общий родительский класс для всех наших
классов. Пусть таким классом будет класс Point. В результате получим иерархию классов,
которая изображена на рисунке (1.3).
У каждого из дочерних классов метод draw переопределен таким образом, чтобы отображать
экземпляры каждого класса соответствующим образом.
Для описанной выше иерархии классов, используя полиморфизм, можно написать
следующий код:
Point p[] = new Point[1000];
p[0] = new Circle();
p[1] = new Point();
p[2] = new Box();
p[3] = new Line();
for(int i = 0; i < p.length;i++){
if(p[i]!=null) p.draw();
}
В описанном выше примере массив p[] может содержать любые объекты, порожденные
от наследников класса Point. При вызове какого-либо метода у любого из элементов этого
массива будет выполнен метод того объекта, который содержится в ячейке массива.
Например, если в ячейке p[0] находится объект Circle, то при вызове метода draw
следующим образом
p[0].draw()
нарисуется круг, а не точка.
В заключение приведем формальное определение полиморфизма:
Полиморфизм (polymorphism) - положение теории типов, согласно которому имена
(например, переменных) могут обозначать объекты разных (но имеющих общего родителя)
классов. Следовательно, любой объект, обозначаемый полиморфным именем, может по-
своему реагировать на некий общий набор операций[1].
В процедурном программировании тоже существует понятие полиморфизма, которое
отличается от рассмотренного механизма в ООП. Процедурный полиморфизм предполагает
возможность создания нескольких процедур или функций с одинаковым именем, но разными
количеством или типами передаваемых параметров. Такие одноименные функции
называются перегруженными, а само явление - перегрузкой (overloading). Перегрузка
функций существует и в ООП и называется перегрузкой методов.
Примером использования перегрузки методов в языке Java может служить класс PrintWriter,
который используется в частности для вывода сообщений на консоль. Этот класс имеет
множество методов println, которые различаются типами и/или количеством входных
параметров. Вот лишь несколько из них:
void println() // переход на новую строку
// выводит значение булевской переменной (true или false)
void println(boolean x)
void println(String x) // выводит строку - значение текстового параметра
Определенные сложности возникают при вызове перегруженных методов. В Java
существуют специальные правила, которые решают эту проблему. Они будут рассмотрены
в соответствующей главе.
Категория: Программирование | Добавил: Admin (19.04.2012)
Просмотров: 5026 | Рейтинг: 2.0/1
Всего комментариев: 0
Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]

Поиск

Вход

Гость
  • Вход
  • Регистрация
  • Читаемое

    Заходи не жди