Автор Анна Евкова
Преподаватель который помогает студентам и школьникам в учёбе.

Применение объектно-ориентированного подхода при проектировании информационной системы (История развития объектно-ориентированного подхода)

Содержание:

ВВЕДЕНИЕ

Врач, строитель и программист поспорили о том, чья профессия древнее. Врач заметил: "В Библии сказано, что Бог создал Еву из ребра Адама. Это мог сделать только хирург, поэтому моя профессия самая древняя в мире". Его пере­бил строитель: "Однако, как сказано в Книге Бытия, еще раньше Бог сотворил из хаоса сначала небо, а потом — землю. Это было первое и, несомненно, наибо­лее впечатляющее строительство. Следовательно, дорогой доктор, вы ошибаетесь. Именно моя профессия самая древняя в мире". Услышав это, программист отки­нулся на спинку кресла, улыбнулся и спросил доверительным тоном: "Ну а кто же, по-вашему, создал хаос?"

"Чем сложнее система, тем она уязвимее". Трудно себе представить стро­ителя, размышляющего, а не вырыть ли еще один подвальный этаж под уже построенным стоэтажным зданием. Такое мероприятие было бы слишком доро­гим и опасным. Как ни странно, пользователи программного обеспечения, не задумываясь, просят делать аналогичные изменения в программах. Более того, он считают, что для программиста эта задача не представляет никаких трудностей.

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

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

  1. Изучить все существующие на данный момент стили программирования.
  2. Выяснить отличительные особенности объектно-ориентированного подхода
  3. Раскрыть основные принципы и понятия объектно-ориентированного подхода
  4. Рассмотреть наиболее распространенные объектно-ориентированные языки программирования.

ГЛАВА 1ТЕОРЕТИЧЕСКИЕ АСПЕКТЫ ПРИМЕНЕНИЯ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПОДХОДА

1.1. История развития объектно-ориентированного подхода

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

Языки процедурного программирования используются до сих пор, наиболее распространенные из них: ассемблер, С, Basic, Pascal.

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

Первым таким языком был LISP.

В языках данного типа основная конструкция – выражение. К ним относятся функции, тела функций, вызовы функций и скалярные константы.

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

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

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

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

Последним из перечисленных типов языков программирования появился объектно-ориентированный подходю

Прототипом объектно-ориентированного программирования послужил ряд средств, входящих в состав языка SIMULA-67. Но в самостоятельный стиль оно оформилось с появлением языка SMALLTALK, разработанного А. Кеем в 1972 году и первоначально предназначенного для реализации функций машинной графики.

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

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

1.2. Основные понятия и принципы ООП

Аналогично тому, как для каждой картины художник использует уникальный набор кистей, так и для каждой отдельной области предпочтителен свой стиль программирования. Например, для проектирования баз зна­ний может оказаться наиболее удобным реляционный стиль, а для решения вычислительных задач — императивный (процедурный). Объектно-ориентированный стиль достаточно неплохо подходит для самого широкого диапазона приложений.

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

  1. Абстракция
  2. Инкапсуляция
  3. Модульность
  4. Иерархия

Термин главный элемент означает, что без любого из них модель не является объектно-ориентированной.

Естественно, программирование на на таких языках, как Smalltalk, Object Pascal, C++, Eiffel или Ada возможно и безприменения объектной модели, однако тогда проект будет похож на программы, написанные на соответствующих процедурных языках. Выразительная мощность объектно-ориентированного языка будет либо утеряна, либо искажена. Кроме того, что еще более важно, в этом случае про­граммисты вряд ли справятся со сложностью задачи.

Абстрагирование — один из основных методов, позволяющих справиться со сложностью. Даль (Dahl), Дейкстра (Dijkstra) и Хоар (Ноаге) утверждают: "Аб­страгирование проистекает из распознавания сходства между определенными объ­ектами, ситуациями или процессами в реальном мире, и является результатом решения сконцентрировать внимание на общих свойствах и проигнорировать раз­личия" [1]. Шоу (Show) считает абстракцией "упрощенное описание, или специ­фикацию системы, выделяющую одни свойства и затеняющую другие, а хорошая абстракция подчеркивает значимые детали и отбрасывает несущественные на дан­ный момент" [2]. Берзинс (Berzins), Грей (Gray) и Науман (Naumann) рекоменду­ют "признавать идею абстракцией только, если она может быть описана, понята и проанализирована независимо от механизма ее дальнейшей реализации" [3]. Объединив все эти точки зрения, можно сформулировать следующее определение абстракции:

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

Абстракция концентрирует внимание на внешнем представлении объекта и по­зволяет отделить существенные особенности поведения от их реализации. Абель-сон (Abelson) и Суссман (Sussman) назвали такое разделение поведения от его реа­лизации принципом минимальных обязательств (principle of least commitment) [4], в соответствии с которым интерфейс объекта должен обеспечивать только суще­ственные аспекты его поведения и ничего больше [5]. Существует также до­полнительный принцип наименьшего удивления (principle of least astonishment), согласно данному принципу абстракция должна полностью описывать поведение объек­та, ни больше и ни меньше.

"Существует целый спектр абстракций, начиная с объектов, почти точно соот­ветствующих реалиям предметной области, и заканчивая совершенно излишними объектами" [6]. Перечислим абстракции в порядке убывания их полезности.

• Абстракция сущности. Объект, представляющий собой полезную модель некой сущности в предметной области.

• Абстракция действия. Объект, состоящий из обобщенного множества операций, каждая из которых выполняет одно­типные функции.

• Абстракция виртуальная Объект, группирующий операции, которые, либо машины вместе используются на более высоком уровне управления, либо сами используют некоторый набор операций более низкого уровня

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

В программировании стараются строить абстракции сущности, так как они прямо соответствуют сущностям предметной области.

Согласно данной концепции объекты делятся на 2 категории – клиенты и серверы. Клиентом называется любой объект, использующий ресурсы другого объекта. А объекта, ресурсы которого используются – называется сервером. Поведение объекта характеризуется услугами, которые он оказывает другим объектам, и операциями, которые он может выполнять над другими объектами. Такой подход концентрирует внимание на внешних проявлениях объекта и приводит к идее, которую Мейер (Meyer) назвал контрактной моделью программирования [7]: внешнее проявление объекта определяет его контракт с другими объектами, подлежащий выполнению его внутренним устройством (часто во взаимодействии с другими объектами). Контракт фиксирует все предположения, которые объект-клиент мо­жет формулировать относительно поведения объекта-сервера. Иначе говоря, кон­тракт определяет ответственность объекта, т.е. его обязательное поведение [8].

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

Главной идеей абстракции является концепция инварианта. Инвариант (in­variant) — это логическое условие (истинное или ложное), которое должно выпол­няться всегда. Для каждой операции, ассоциированной с объектом, можно задать предусловия (инварианты, предполагаемые операцией) и постусловия (инвариан­ты, которым удовлетворяет операция). Нарушение инварианта противоречит кон­тракту, связанному с абстракцией. Если нарушается предусловие, то это значит, что клиент не соблюдает свои обязательства и сервер не в состоянии надежно функционировать. Аналогично, если нарушается постусловие, то свои обязатель­ства не выполняет сервер, так что клиент больше не может ему доверять. При­знаком нарушения некоего инварианта является исключительная ситуация. Неко­торые языки позволяют объектам генерировать исключительные ситуации, чтобы отменить дальнейшую обработку данных и предупредить о возникшей проблеме другие объекты, которые в свою очередь могут перехватывать и обрабатывать исключения.

Заметим, что понятия операция, метод и функция-член происходят из разных языков программирования (Ada, Smalltalk и C++ соответственно). По существу, они обозначают одно и то же и в дальнейшем будут использоваться как синонимы.

У каждой абстракции имеются как статические, так и динамические свойства. Рассмотрим пример. Для файл как объекта требуется определенный объем памяти на конкретном запоминающем устройстве. Кроме того, у него есть имя и содержание. Все эти атрибуты являются статическими свойствами. Значения же всех каждого такого свойства носят динамический характер и зависят от жизненного цикла объек­та. Например, файл можно увеличить или уменьшить, а также изменить его имя и содержимое. Суть всех программ, написанных в процедурном (императивном) стиле, составляют действия, изменяющие динамические характеристики объектов. В таких програм­мах события происходят только в результате вызова подпрограмм и выполнения операторов. С другой стороны, в программах, написанных в стиле, ориентирован­ном на правила, события происходят только тогда, когда определенные условия приводят в действие установленные правила, которые, в свою очередь, активизи­руют другие правила, и т.д. В программах, написанных в объектно-ориентирован­ном стиле, события связаны с воздействием на объекты (т.е. с передачей объектам определенных сообщений). Выполнение операции над объектом вызывает у него определенную реакцию. Поведение объекта полностью определяется операциями, которые над ним можно выполнять, и его реакцией на внешние воздействия.

Абстракция и инкапсуляция дополняют друг друга. Если внимание аб­стракции сосредоточено на наблюдаемом поведении объекта, то инкапсуляция сосредото­чена на реализации, обеспечивающей заданное поведение. Как правило, инкапсу­ляция осуществляется с помощью сокрытия информации (а не просто сокрытия данных), т.е. утаивания всех несущественных деталей объекта. Обычно скрывают­ся как структура объекта, так и реализация его методов. "Никакая часть сложной системы не должна зависеть от внутреннего устройства какой-либо другой части" [9]. В то время как абстракция "помогает людям думать о том, что они делают", инкапсуляция "позволяет легко перестраивать программы" [10].

Инкапсуляция определяет четкие границы между разными абстракциями и поз­воляет, таким образом, провести ясные различия между понятиями. Рассмотрим, например, структуру растения. Для того чтобы изучить механизм фотосинтеза, оставаясь на верхнем уровне абстракции, можно игнорировать такие детали, как функции корней растения или химические свойства стенок клеток. Аналогич­но, при проектировании баз данных принято писать программы так, чтобы они зависели не от физического представления данных, а от логической структуры данных [11]. Легко заметить, что данные примеры аналогичны тем, что объекты, расположенные на одном уровне абстрак­ции, защищены от деталей реализации объектов, относящихся к более низкому уровню.

"Для того чтобы абстракция работала, ее реализация должна быть инкапсули­рована" [12]. С практической стороны это означает, что каждый класс должен состоять из двух частей: интерфейса и реализации. В интерфейсной части класса обозначено лишь внешнее представление объекта, описывая абстракцию поведения всех объектов данного класса. Реализация же класса содержит как представление абстракции, так и меха­низмы достижения требуемого поведения объекта. Интерфейс класса содержит все предположения, которые клиент может сформулировать относительно объек­тов класса, а реализация скрывает от других объектов все детали, не имеющие отношения к процессу — все, что не касается предположений клиента.

Из вышеуказанного объяснения можно свормулировать определение инкапсуляции.

Инкапсуляция — это процесс разделения элементов абстракции, опре­деляющих ее структуру и поведение; инкапсуляция предназначена для изоляции контрактных обязательств абстракции от их реализа­ции.[1]

"Разделение программы на модули до некоторой степени позволяет умень­шить ее сложность... Однако гораздо важнее тот факт, что при этом в модульной программе возникает множество хорошо определенных и документированных ин­терфейсов. Эти интерфейсы неоценимы для понимания программы" [14]. В неко­торых языках программирования, например в Smalltalk, модулей нет, и един­ственной физической единицей декомпозиции является класс. Во большинстве других языков (например Object Pascal, C++) модуль — это самостоятельная языко­вая конструкция, позволяющая создавать комплексы отдельных проектных реше­ний. В таких языках логическая структура системы состоит из классов и объектов. Она помещается в модули, из которых состоит физическая структура системы. Это свойство особенно полезно в крупных системах, состоящих из многих сотен классов.

"Модульность — это разделение программы на фрагменты, которые компили­руются по отдельности, но связаны между собой". В соответствии с определением Парнаса (Parnas): "Связи между модулями — это их предположения о работе друг друга" [15]. В большинстве языков, поддерживающих принцип модульности как самостоятельную концепцию, интерфейс модуля отделен от его реализации. Та­ким образом, можно утверждать, что модульность и инкапсуляция тесно связаны между собой.

Правильный выбор модулей для решения поставленной задачи является почти такой же сложной задачей, как выбор правильного набора абстракций. Зельковиц (Zelkowitz) был абсолютно прав, утверждая: "Поскольку в начале работы над про­ектом решение может быть неясным, декомпозиция на более мелкие модели может вызвать затруднения. Для традиционных приложений (например, разработки ком­пиляторов) этот процесс можно стандартизировать, но для новых задач (например, оборонительных систем или систем управления космическими кораблями) задача может оказаться довольно трудной" [16].

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

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

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

Существует несколько эмпирических приемов и правил, позволяющих обеспе­чить разумную модульность. Бриттон (Britton) и Парнас (Parnas) утверждают: "Ко­нечной целью декомпозиции программы на модули является снижение затрат на программирование, благодаря независимому проектированию и тестированию... Структура каждого модуля должна быть достаточно простой для понимания, до­пускать независимую реализацию других модулей и не влиять на поведение дру­гих модулей, а также позволять легкое изменение проектных решений" [17]. На практике эти принципы реализуются лишь частично. Повторное компилирование тела отдельного модуля не требует больших затрат, поскольку остальные модули остаются неизменными, а обновляются только связи между ними. Однако стои­мость повторной компиляция интерфейса модуля относительно велика. В языках программирования со строгим контролем типов приходится повторно компилиро­вать интерфейс и тело модифицированного модуля, затем все зависимые модули и т.д. В итоге для очень больших программ повторная компиляция может оказать­ся очень долгой (если только среда разработки не поддерживает инкрементную компиляцию), что явно нежелательно. Очевидно, руководитель проекта не должен допускать слишком частую повторную компиляцию. По этой причине интерфейс модуля должен быть как можно более узким (обеспечивая, тем не менее, необхо­димые связи с другими модулями). Правильный стиль программирования требует как можно больше скрывать реализацию модуля. Постепенный перенос описаний из реализации в интерфейс гораздо безопаснее, чем удаление излишнего интер­фейсного кода.

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

Модульность — это свойство системы, разложенной на цельные, но слабо связанные между собой модули.

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

Разделение системы на модули имеет два дополнительных аспекта. Во-первых, поскольку модули, как правило, являются элементарными и неделимыми струк­турными элементами программного обеспечения и могут использоваться в при­ложениях неоднократно, разделение программы на модули должно допускать по­вторное использование кода. Во-вторых, многие компиляторы создают отдельные сегменты кода для каждого модуля. Следовательно, могут возникнуть физические ограничения на размер модуля. Динамика вызовов подпрограмм и размещение объявлений внутри модулей могут существенно влиять на локальность ссылок и на управление страницами виртуальной памяти. Вызовы между несмежными сегментами приводят к "промахам кэша" (cashe miss) и порождают режим ин­тенсивной подкачки страниц памяти (trashing), что в итоге тормозит работу всей системы.

Разбиение на модули должно учитывать дополнительные факторы, не носящие технического характера. Как правило, распределение работы между участниками проектной группы осуществляется по модульному принципу. Следовательно, си­стему необходимо разделять на модули так, чтобы минимизировать количество связей между участниками проекта. Опытные программисты обычно отвечают за разработку интерфейсов модулей, а менее опытные — за их реализацию. Анало­гичная ситуация наблюдается в более крупном масштабе в отношениях между субподрядчиками. Распределение абстракций должно облегчать быстрое согласо­вание интерфейсов модулей между компаниями, участвующими в проекте. Изме­нения интерфейсов, уже согласованных между компаниями, обычно сопровожда­ются воплями и зубовным скрежетом — помимо огромного расхода бумаги, — по­этому проектирование интерфейса является крайне консервативным делом. Кроме того, модуль служит отдельной единицей документации и администрирования. Десять модулей требуют в десять раз больше описаний, чем один, и поэтому, к сожалению, иногда на декомпозицию проекта влияют (как правило, негатив­но) побочные соображения, связанные с составлением проектной документации. На модульность проекта может влиять его секретность. Например, большая часть кода может считаться открытой, а остальная часть — секретной. В таком случае секретную часть размещают в отдельных модулях.

Согласовать эти противоречивые требования довольно трудно, но следует пом­нить главное: выявление классов и объектов, с одной стороны, и организация их в виде отдельных модулей, с другой стороны, — это практически независи­мые проектные решения. Идентификация классов и объектов представляет собой часть логического проектирования системы, а идентификация модулей — часть ее физического проектирования. Разумеется, невозможно полностью осуществить логическое проектирование системы до реализации физического проектирования, и наоборот. Два этих процесса носят итеративный характер.

Абстракция — вещь полезная, но количество абстракций всегда, кроме самых тривиаль­ных приложений, намного превышает человеческие возможности. Инкапсуляция, скрыв внутреннее представление абстрак­ций, немного снижает эту сложность. Модульность также упрощает понимание проблемы, позволяя объединить логически связанные абстракции в группы.

Определим иерархию следующим образом.

Иерархия — это упорядочение абстракций.

Наиболее важными видами иерархии в сложных системах являются структу­ра классов (иерархия "общее/частное") и структура объектов (иерархия "целое/ часть").

Иерархия подразумевает наследование.

Наследование представляет собой одну из наиболее важных иерархий, основанных на отношении "является". Оно лежит в основе многих объектно-ориентированных систем. Концепция наследования определяет такое отношение между классами, когда один класс заимствует структуру другого класса (одиночное наследование), либо нескольких других классов 9множественное наследование). Другими словами, наследование создает иерархию абстракций, в которой подклассы заимствуют свойства одного или нескольких суперклассов. Обычно подкласс увеличивает или переопределяет существующую структуру и по­ведение суперкласса.

С семантической точки зрения, наследование описывает отношение типа "яв­ляется". Например, медведь — это разновидность, дом — это разновидность материальных активов, а метод быстрой сортировки — это разновидность алгоритма сортировки. Таким образом, наследование порождает иерар­хию обобщения/специализации, в которой подкласс конкретизирует более общую структуру или поведение своего суперкласса. Действительно, существует безоши­бочный тест для наследования: если класс В не является разновидностью класса А, то класс В не должен быть наследником класса А.

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

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

Наследование позволяет создавать новые программы точно так же, как вводятся новые понятия — сравнивая новое с уже известным" [17].

Между принципами абстракции, инкапсуляции и иерархии существует здоро­вая конкуренция. "Абстракция данных создает непроницаемый барьер, скрываю­щий методы и состояние объекта. Принцип наследования требует открыть доступ и к состоянию, и к методам объекта, не прибегая к абстракции" [18]. У любого класса обычно существуют два вида клиентов: объекты, выполняющие операции над экземплярами данного класса, и подклассы, наследующие свойства класса. Лисков (Liskov) отмечает, что существуют три способа нарушения инкапсуляции с помощью наследования: "подкласс может получить доступ к переменным эк­земпляра своего суперкласса, вызвать закрытую функцию и, наконец, обратиться напрямую к суперклассу своего суперкласса" [19]. Разные языки программирова­ния по-разному согласовывают наследование с инкапсуляцией. Наиболее гибкими в этом отношении являются C++ и Java. В частности, интерфейс класса может состоять из трех частей: закрытой (private), доступной только самому классу; за­щищенной (protected), в которой объявляются члены, доступные только для класса и его подклассов; и открытую (public), доступную всем клиентам.

ГЛАВА 2. МЕТОДОЛОГИЯ ООП

2.1 Объектно-ориентированный анализ (ООА)

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

Модели OOA в дальнейшем преобразуются в объектно-ориентированный проект.

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

  1. Инкапсуляция

Инкапсуляция позволяет во многом изолировать класс от остальных частей программы, сделать его «самодостаточным» для решения конкретной задачи. В результате класс всегда несет в себе некоторую функциональность. Например, класс TForm в Delphi содержит (инкапсулирует в себе) все необходимое для создания Windows-окна, класс TTimer обеспечивает работу таймера и т.д.

Единицей инкапсуляции в OOD является объект.

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

Любой класс может быть порожден от другого класса. Для этого при его объявлении указывается имя класса-родителя:

TChildClass = class(TParentClass) (язык Object Pascal)

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

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

Таким образом, полиморфизм проводит идею «один интерфейс – множество методов». Выбор конкретного действия зависит от ситуации.

2.3 Объектно-ориентированное программирование (ООР)

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

Фундаментальная концепция OOP заключается в том, что взаимодействие классов и объектов между собой происходит посредством передачи и приема сообщений. Для реализации обмена, необходимо, чтобы объекты определялись вместе с сообщениями, на которые они реагируют. Этим ООР отличается от императивного стиля программирования, в котором сначала определяются данные, а затем эти даны передаются в функции, или процедуры, как параметры. При этом средством программирования выступает один из объектно-ориентированных языков программирования. Язык программирования называется объектно-ориентированным, если есть поддержка объектов как абстракций данных, имеющих интерфейсную часть в виде поименованных операций, и защищенную область локальных данных; все объекты относятся к соответствующим типам (классам); классы могут наследоваться от суперклассов.

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

Последний принцип отличает чистые объектно-ориентированные языки такие как Smalltalk, Actor, от гибридных языков программирования, выросших из ранее существовавших процедурных языков (Object Pascal, C++). Данные подходы – две крайности в множестве объектно-ориентированных языков. Примерно в середине находится новый, полностью построенный на принципах объектно-ориентированной идеологии, однако нарушающий последний принцип, язык Java.

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

2.4 Объектно-ориентированные языки

Использование объектно-ориентированной технологии не ограничивается каким-то конкретным языком программирования. Она реализуется во многих объектных и объектно-ориентированных языках. Однако программирование является не менее важным аспектом, чем анализ и проектирование. Нельзя пренебрегать деталями кодирования поскольку в конце концов архитектурные особенности систем должны быть выражены с помощью какого-то конкретного языка программирования. Как полагает Вульф (Wulf) [1], язык программирования служит трем целям.

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

В настоящее время существуют более 2 500 разных языков программирования высокого уровня. Это разнообразие объясняется тем, что каждый из этих языков разрабатывался для использования в определенных предметных областях. Более того, появление очередного нового языка программирования позволяет разработчикам приступить к решению все более и более сложных задач. Исследуя ранее не изученные области применения, разработчики языков получили возможность уточнить свои представления о том, что важно для языка программирования, а что нет. Кроме того, на эволюцию языков программирования значительное вли­яние оказали достижения теории вычислений, которые позволили формализовать семантику операторов, модулей, абстрактных типов данных и процессов.

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

Общим предком почти всех современных объектных и объектно-ориентиро­ванных языков является язык Simula, разработанный в 1960-х годах Даалем (Dahl), Мирхургом (Myrhurg) и Нигардом (Nygard). Язык Simula развил идеи языка ALGOL, дополнив их концепцией инкапсуляции и наследования. Вероятно, наи­более важным обстоятельством является то, что язык Simula, предназначенный для моделирования и описания систем, заложил правила написания программ, отражающие словарь изучаемой предметной области.

Генеалогия наиболее важных и распространенных объектных и объектно-ори­ентированных языков программирования продемонстрирована на рис. 1, заим­ствованном с Web-сайта Эрика Левенеца (Eric Levenez), посвященного истории языков программирования. Величина прямоугольника отражает интенсивность разработки или использования языков в общей предметной области, а стрелочки изображают влияние, которое языки оказывали на разработку других языков.

Рисунок 1 – Генеалогия наиболее важных языков программирования.

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

Одним из новаторских способов оценки популярности языков программиро­вания является индекс программистского сообщества ТIOВЕ (TCP-Index). Он основан на сканировании Web-страниц и групп новостей в сети Интернет. Исполь­зуя простые запросы, касающиеся исследуемого языка программирования, можно определить процентную долю Web-страниц, представляющих интерес, и сравнить эти результаты с данными, полученными ранее, по месяцам и годам. В таблице 1 приведены результаты данного исследования за октябрь 2013 года.

Таблица 1 Результаты определения популярности современных языков программирования.

Место

Язык программирования

Рейтинг, %

1

C

17.246%

2

Java

16.107%

3

Objective-C

8.992%

4

C++

8.664%

5

PHP

6.094%

6

C#

5.718%

7

(Visual) Basic

4.819%

8

Python

3.107%

9

Transact-SQL

2.621%

10

JavaScript

2.038%

11

Visual Basic .NET

1.933%

12

Perl

1.607%

13

Ruby

1.246%

14

Pascal

0.753%

15

PL/SQL

0.730%

16

Lisp

0.725%

17

Delphi/Object Pascal

0.701%

18

Groovy

0.658%

19

MATLAB

0.614%

20

COBOL

0.599%

Ниже описаны наиболее важные языки программирования.

Язык Smalltalk был разработан членами исследовательской группы Xerox Palo Alto Research Center Learning Research Group как элемент утопического проекта Dynabook, предложенного Аланом Кэем (Alan Kay). Основное влияние на этот проект оказали идеи языка программирования Simula, хотя в определенной степени в нем использовались принципы языка FLEX, а также результаты работ Сеймура Пэперта (Seymore Papert) и Уаллеса Фойрзайга (Wallace Feurzeig). Smalltalk представляет собой и язык программирования, и среду разработки программ. Он является чисто объектно-ориентированным языком программирования, в котором абсолютно все сущности считаются объектами. Даже целые числа в языке Smalltalk представляют собой классы. Наряду с языком Simula язык Smalltalk является, вероятно, важнейшим объектно-ориентированным языком программирования, поскольку его идеи оказали влияние не только на практически все последующие языки программирования (хотя сам Smalltalk теперь используется редко), но и легли в основу современных графических интерфейсов пользователя, таких как Macintosh, Windows, KDE и Gnome, получивших общее признание.

Существуют пять версий этого языка: Smalltalk-72, 74, 76, 78, 80. Версии Smalltalk-72 и 74 не поддерживали наследование, но реализовывали большинство основных концепций, в частности, механизм передачи сообщений и полиморфизм. В последующих версиях на первый план вышли классы. Это свидетельствовало о победе точки зрения, что все сущности в среде программирования должны рассматриваться как объекты. В настоящее время существует около 20 разных реализаций языка Smalltalk, большинство из которых представляют собой вариант языка Simula-80 для конкретной платформы (аппаратного и программного обеспечения). Несмотря на то, что пользовательский интерфейс в этих реализациях, как правило, отличается от других, библиотеки классов и общие функциональные свойства во всех версиях практически совпадают.

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

Таблица 2 Объектно-ориентированные свойства Smalltalk

Элементы объектной модели

Свойство

Включено?

Абстракция

Переменные экземпляра

да

Методы экземпляра

Да

Переменные класса

Да

Методы класса

Да

Инкапсуляция

Переменных

Закрытая

Методов

Открытая

Модульность

Виды моделей

Нет

Иерархия

Наследование

Одиночное

Шаблоны

Нет

Метаклассы

Да

Язык программирования C++ разработал сотрудник компании AT&T Bell Laboratories Бьерн Страуструп (Bjarne Stroustrup). Непосредственным предшествен­ником C++ является язык С with Classes, созданный Страуструпом в 1980 году. В свою очередь, язык С with Classes испытывал сильное влияние языков С и Si­mula. В значительной степени язык C++ представляет собой расширение языка С. Однако в некотором смысле язык C++ лучше языка С. В частности, он обеспе­чивает контроль типов, перегрузку функций и ряд других усовершенствований. И все же самое главное — это то, что язык C++ добавляет к языку С объектно-ориентированные свойства.

Ранние технологии трансляции программ, написанных на языке C++, исполь­зовали препроцессор cfront языка С. Поскольку в качестве промежуточного кода препроцессор cfront генерировал программы на языке С, он позволил достаточ­но быстро перенести язык C++ практически на все UNIX-системы. В настоящее время почти на всех платформах существуют коммерческие трансляторы и ин­терпретаторы языка C++, которые могут настраиваться практически на любую архитектуру компьютеров.

Существовало несколько основных версий C++. Версия 1.0 дополнила язык С механизмами объектно-ориентированного программирования, например, одиноч­ным наследованием и полиморфизмом, а также проверкой типов и перегрузкой функций. Версия 2.0, выпущенная в 1989 году, представляла собой улучшенную версию своей предшественницы (в частности, в этой версии было реализовало множественное наследование). Она возникла в результате обобщения опыта ши­рокого применения языка C++ довольно крупным сообществом пользователей. В версии 3.0, появившейся в 1990 году, были предусмотрены шаблоны (парамет­ризованные классы) и обработка исключений. Комитет ANSI X3J16 C++ одоб­рил предложения по управлению пространствами имен (согласованные с нашим понятием категории классов), а также идентификации типов во время выполне­ния программ. Кроме того, язык C++ был стандартизован Британским институ­том стандартов (BTI — British Standards Institute), Организацией национальных стандартов Германии (German national standards organization — DIN) и Органи­зацией международных стандартов (International Standards Organization — IOS). Окончательный вариант стандарта ISO был принят в 1997 году и ратифицирован в августе 1998 года. В настоящее время основным институтом, отвечающим за поддержку стандарта языка C++, является организация ISO.

Язык C++ исправил многие недостатки языка С. В нем предусмот­рены описания классов, проверка типов, перегрузка, управление динамической памятью, постоянные типы, ссылки, встраиваемые функции, производные классы и виртуальные функции.

Характеристики языка C++ с точки зрения четырех основных элементов объект­ного подхода приведены в таблице З.

Таблица З. Объектно-ориентированные свойства языка C++

Элементы объектной модели

Свойство

Включено?

Абстракция

Переменные экземпляра

Да

Методы экземпляра

Да

Переменные класса

Да

Методы класса

Да

Инкапсуляция

Переменных

Закрытая, защищенная, закрытая

Методов

Открытая, защищенная, закрытая

Модульность

Виды моделей

Файл

Иерархия

Наследование

Множественное

Шаблоны

Да

Метаклассы

Нет

Выяснив, что с помощью языка C++ очень трудно решить некоторые задачи, Джеймс Гослинг (James Gosling) и его немногочисленные коллеги, работавшие в компании Sun Microsystems, создали компактный язык программирования под названием Oak.

Перед группой Джеймса Гослинга стояла задача разработать программное обеспечение для бытовых приборов с цифровым управлением, например, элек­тронных игрушек и микроволновых печей. После того как попытки внедрить эту технологию на рынке цифрового кабельного телевидения провалились, разработ­чики поняли, что наилучшая сфера для приложения их усилий — сеть Интернет. Авторы переименовали язык Oak в язык Java и стали позиционировать его как язык программирования общего назначения, интерпретаторы которого легко за­грузить через сеть Интернет и выполнить в контексте браузеров HTML.

Решающий прорыв языка Java на рынок произошел в 1995 году, когда компа­нии Sun Microsystems и Netscape сообщили, что они планируют инкорпорировать технологию Java в программу Netscape Navigator, наиболее популярный браузер того времени. Сообщение сразу привело к созданию огромного рынка потенци­альных пользователей этой технологии.

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

Несмотря на относительную молодость языка Java (менее 20 лет), его успешность феноменальна со многих точек зрения, при чем его популярность продолжает расти до сих пор. Этот рост можно объяснить не только постоянным совершенствованием языка, но и появлением тесно связанных с ним технологий: Enterprise Java Beans (EJB), Java Server Pages (JSP) и Java 2 Micro Edition (J2ME).

В данное время компания Sun Microsystems активно развивает язык Java и свя­занные с ним технологии.

Технология Java — это не просто язык программирования. Подобно языку Smalltalk, Java одновременно является и средой программирования, и языком. Ja­va основывается на использовании виртуальных машин и промежуточного двоичного кода. Аналогично языку Smalltalk, язык Java содержит в себе объемную библиотеку классов, ко­торую можно дополнять. Технология Java очень хорошо подходит для сети Интернет в виду своей независимости от компьютерной плат­формы и богатому набору стандартных функций.

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

Однако, в языке Java нет многих свойств языка C++, например множественного наследования и перегрузки операторов. Однако имеются и такие свойства и механизмы, которые впервые появились именно в этом языке. Одним из наиболее важных свойств языка Java является сборка "мусора" (garbage collection). Этот механизм освобождает разработчиков языка Java от необходимости реализовывать свою собственную си­стему управления памятью. Вместо этого они могут создавать новые экземпляры объектов и быть уверенными, что после удаления всех ссылок некоторая область памяти будет очищена. Несмотря на то что этот механизм сборки "мусора" не так эффективен, как механизм управления памятью в языке C++, он устраняет источники многих потенциальных ошибок.

Язык Java стремится обеспечить максимально возможную с точки зрения прак­тики безопасность типов. Однако, благодаря обширной библиотеке классов, такая строгая проверка типов, как в языке C++, не является практичной. Самая свежая спецификация языка Java 2 version 1.5 содержит некоторые новшества, которые называются Generics (JSR 14). Классы Java Generics, известные также как пара­метризованные типы, похожи на шаблоны из языка C++. Они позволяют про­граммистам, работающим на языке C++, помимо всего прочего создавать наборы данных (collections), безопасные с точки зрения типов.

Характеристики языка Java относительно четырех основных элементов объект­ного подхода приведены в таблице 4.

Таблица 4 – Объектно-ориентированные свойства Java

Элементы объектной модели

Свойство

Включено?

Абстракция

Переменные экземпляра

Да

Методы экземпляра

Да

Переменные класа

Да

Методы класса

Да

Инкапсуляция

Переменных

Открытая, защищенная, закрытая, пакет

Методов

Открытая, защищенная, закрытая, пакет

Модульность

Виды моделей

Файл

Иерархия

Наследование

Одиночное

Шаблоны

Да

Метаклассы

Нет

ЗАКЛЮЧЕНИЕ

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

Кроме того, были рассмотрены основные понятия объектно-ориентированной методологии, а именно абстракция, инкапсуляция, иерархичность и модульность.

Также были рассмотрены наиболее популярные объектно-ориентированные языки, раскрыты их особенности.

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

СПИСОК ЛИТЕРАТУРЫ

  1. Гради Буч «Объектно-ориентированный анализ и проектирование», Rational Санта-Клара, Калифорния перевод с английского под редакцией И. Романовского и Ф. Андреева, 2008 г.
  2. Йорден Е, Методы структурного моделирования. Росса-М, 2009 г.
  3. Ган. С и Сарсон, Т. Системы структурного анализа, ТехноРос, 2009 г.
  4. Уорд, П. и Меллор, С.. Структурированные развития систем реального времени. 2010 - Мир, Москва, 560с.
  5. Хэтли, Д. Стратегии системных спецификаций. Нью-Йорк, Дорсет дом., М- 2008.
  6. Дженкинс, М. и Глазго, Дж. 2006 О Стилях программирования в Ниал . IEEE Software вып.3 (1) , стр.48 .
  7. Боброва,Д. и Стэфик,М. феврале 1006 года. Перспективы программировании искусственного интеллекта . вып. 231 Наука, с.51 .
  8. Даль, О., Дейкстра Э., Хоара , C.A.R. Структурное программирование. Академик-пресс., М-2012, с.83 .
  9. Шоу, М. Абстракция методы в современной Языки программирования. IEEE Software вып (4) , 2004. с.10 .
  10. Берзиньш ,В. Грей ,М. и Науман,Д. Абстракция на основе разработки программного обеспечения. Объекдинение, 2006. вып. 29 (5) , с.403 .
  11. Абельсона , Х. и Суссман , Г. Структура и интерпретация компьютерных программ, Лига-пресс, М – 1985, с.126 .
  12. Там же, с.132 .
  13. Ингаллс, Д. Smalltalk -76 Программирование разработки и внедрения систем. Результаты Пятого ежегодного симпозиума о принципах Языков программирования. ACM , стр.9 .
  14. Ганнон .Дж . , Гамлет . Р. Миллс. H. Теории модулей . IEEE Transactions номер 13 (7) , с.820 .
  15. Date, С. 2006. Relational Database: Selected Writings. Reading, MA: Addison-Wesley, p.180.
  16. Liskov, B. 2008. Data Abstraction and Hierarchy. SIGPLAN Notices vol.23(5). p.19