Вконтакте Facebook Twitter Лента RSS

Ооп наследование инкапсуляция полиморфизм. Объектно-ориентированное программирование (ООП): полиморфизм

JAVA основывается на концепциях объектно-ориентированного программирования, что позволяет перейти на более высокий уровень абстракции, чтобы разрешить любую проблему реалистичным путем. Объектно-ориентированный подход концептуализирует решение проблемы в плоскости объектов реального мира, которые легче повторно использовать в приложении. Например, Chair (стул), Fan (вентилятор), Dog (Собака), Computer (компьютер) и так далее. В JAVA класс представляет собой макет, шаблон или прототип, который определяет общее поведение объекта данного типа. Экземпляр - это отдельная реализация класса, и все экзепляры класса имеют одинаковые свойства, которые описаны в определении класса. Например, вы можете опрделить класс с именем House (дом) с количеством комнат в качестве атрибута и создать экземпляры класса, такие как дом с двумя комнатами, дом с тремя комнатами и так далее. Преимущества: Ниже перечислены некоторые плюсы объектно-ориентированной разработки программного обеспечения (ПО).

  • Снижение затрат на поддержку ПО, в основном за счет того, что она осуществляется модульно.
  • Усовершенствованное повторное использование кода благодаря таким качествам, как наследование, и, как результат, более быстрая разработка ПО.
  • Повышенные надежность и гибкость кода.
  • Легкость понимания вследствие моделирования реального мира.
  • Лучшая абстракция на уровне объекта.
  • Уменьшение сложности перехода от одной фазы разработки к другой.
Есть четыре основные характеристики ООП:
  • Инкапсуляция
  • Наследование
  • Полиморфизм
  • Абстракция

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

Инкапсуляция выступает договором для объекта, что он должен скрыть, а что открыть для доступа другими объектами. В JAVA мы используем модификатор доступа private для того, чтобы скрыть метод и ограничить доступ к переменной из внешнего мира. JAVA также располагает различными модификаторами доступа: public , по умолчанию, protected , private , которые используются для ограничения видимости на разных уровнях. Но конечной целью является инкапсуляция тех вещей, которые не должны быть изменены. Лучше всего работает подход, при котором, у класса должна быть только одна причина для изменения, и инкапсулирование воплощает в реальность проектирование этой “одной причины”. Правильным в инкапсуляции считается сокрытие часто изменяющихся вещей во избежание повреждения других классов. Преимущества: Ниже представлены некоторые преимущества инкапсуляции:
  • Мы можем защитить внутреннее состояние объекта с помощью сокрытия его атрибутов.
  • Это улучшает модульное построение кода, так как предотвращает взаимодействие объектов неожиданными способами.
  • Повышается практичность кода.
  • Это поддерживает договорные отношения конкретного объекта.
  • Инкапсуляция облегчает поддержку ПО.
  • Изменения в коде могут производиться независимо друг от друга.

Полиморфизм

Полиморфизм в программировании - это способность предоставлять один и тот же интерфейс для различных базовых форм (типов данных). Это означает, что классы, имеющие различную функциональность, совместно используют один и тот же интерфейс и могут быть динамически вызваны передачей параметров по ссылке. Классический пример - это класс Shape (фигура) и все классы, наследуемые от него: square (квадрат), circle (круг), dodecahedron (додекаэдр), irregular polygon (неправильный многоугольник), splat (клякса) и так далее. В этом примере каждый класс будет иметь свой собственный метод Draw() и клиентский код может просто делать: Shape shape = new Shape () ; Shape.area() чтобы получить корректное поведение любой фигуры Красота полиморфизма заключается в том, что код, работая с различными классами, не должен знать, какой класс он использует, так как все они работают по одному принципу. Процесс, применяемый объектно-ориентированными языками программирования для реализации динамического полиморфизма, называется динамическим связыванием. Примечание: Полиморфизм - это способность выбирать более конкретные методы для исполнения в зависимости от объекта. Полиморфизм осуществляется тогда, когда не задействованы абстракные классы. Преимущества:
  • Создание повторно используемого кода. То есть, как только класс создан, реализован и протестирован, он может свободно использоваться без заботы о том, что конкретно в нем написано.
  • Это обеспечивает более универсальный и слабосвязанный код.
  • Понижается время компиляции, что ускоряет разработку.
  • Динамическое связывание.
  • Один и тот же интерфейс может быть использован для создания методов с разными реализациями.
  • Вся реализация может быть заменена с помощью использования одинаковых сигнатур метода.
Переопределение методов как часть полиморфизма. Переопределение взаимодействует с двумя методами: методом родительского класса и методом производного класса. Эти методы имеют одинкавые имя и сигнатуры. Переопределение позволяет вам производить одну и ту же оперецию различными путями для разных типов объектов. Например: while (it. hasNext () ) { Shape s = (Shape) it. next () ; totalArea += s. area (dim) ; //будет применен полиморфизм и вызван нужный метод для каждого объекта. } Перезагрузка методов или ad-hoc полиморфизм или статический полиморфизм Перезагрузка взаимодействует с несколькими методами одного класса, которые одинаково названы, но имеют разные сигнатуры методов. Перезагрузка позволяет вам описать одну и ту же операцию различными путями для разных данных. Иногда ее называют статическим полиморфизмом, но фактически полиморфизмом она не является. Это ничто иное, как просто наличие двух методов с одинаковыми именами, но разным списком аргументов. Перезагрузка не имеет ничего общего с наследованием и полиморфизмом. И перезагруженный метод совсем не то же самое, что переопределенный метод. Параметрический полиморфизм через обобщение в JAVA При объявлении класса поле имени может ассоциироваться с различными типами, а имя метода может ассоциироваться с различными параметрами и возвращаемыми типами. JAVA поддерживает параметрический полиморфизм, применяя обобщение (дженерики). List< String> list = new ArrayList < String> () ; Почему мы не можем переопределить статический метод в JAVA? Переопределение зависит от наличия экземпляра класса. Идея полиморфизма состоит в том, что вы можете создать подкласс, и объекты, реализуемые теми подклассами, будут вести себя по-другому с теми же методами родителького класса (переопределенными в подклассах). Статический метод не ассоциируется ни к каким экземпляром класса, таким образом, сама концепция переопределения не может быть применена. Создателями JAVA руководили два соображения, которые повлияли на такой подход. Во-первых, это проблемы исполнения кода: лилось очень много критики в адрес Smalltalk из-за медленной работы (сборщик мусора и полиморфизм были частью этой проблемы), и в проектировании JAVA старались этого избежать. Вторым соображением было решение, что целевой аудиторией JAVA станут С++ разработчики. То, что статические методы работают именно таким образом, было очень знакомо C++ программистам, а так же ускоряло работу, так как не было необходимости проходить вверх по иерархии классов, чтобы выяснить, какой метод вызывать. Вы идете прямо к классу и вызываете конкретный метод.

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

Наследование - это включение поведения (т.е. методов) и состояния (т.е. переменных) базового класса в производный класс, таким образом они становятся доступны в этом производном классе. Главное преимущество наследования в том, что оно обеспечивает формальный механизм повторного использования кода и избегает дублирования. Унаследованный класс расширяет функциональность приложения благодаря копированию поведения родительского класса и добавлению новых функций. Это делает код сильно связанным. Если вы захотите изменить суперкласс, вам придется знать все детали подклассов, чтобы не разрушить код. Наследование - это форма повторного использования программного обеспечения, когда из уже существующего класса (суперкласса) создается новый класс (подкласс), который расширяет свою функциональность и при этом использует некоторые свойства суперкласса. Так что, если у вас есть класс-родитель, а потом появляется класс-наследник, то наследник наследует все вещи, которыми обладает родитель. Преимущества:
  • Усовершенствованное повторное использование кода.
  • Устанавливается логическое отношение «is a» (является кем-то, чем-то). Например: Dog is an animal . (Собака является животным).
  • Модуляризация кода.
  • Исключаются повторения.
Недостаток:
  • Сильная связанность: подкласс зависит от реализации родительского класса, что делает код сильно связанным.
Что еще почитать:

Абстракция

Абстракция означает разработку классов исходя из их интерфейсов и функциональности, не принимая во внимание реализацию деталей. Абстрактный класс представляет собой интерфейсы без включения фактической реализации. Он отличает реализацию объекта от его поведения. Абстракция упрощает код, скрывая несущественные детали. Преимущества:
  • Применяя абстракцию, мы можем отделить то, что может быть сгруппировано по какому-либо типу.
  • Часто изменяемые свойства и методы могут быть сгруппированы в отдельный тип, таким образом основной тип не будет подвергаться изменениям. Это усиливает принцип ООП: «Код должен быть открытым для Расширения, но закрытым для Изменений» .
  • Абстракция упрощает представление доменных моделей.
Отличие между абстракцией и инкапсуляцией Инкапсуляция - это стратегия, используемая как часть абстракции. Инкапсуляция относится к структуре объекта: объекты инкапсулируют свои свойства и скрывают их от доступа извне. Пользователи класса взаимодействуют с ним с помощью его методов, но не имеют доступа напрямую к структуре класса. Таким образом класс абстрагирует детали реализации, относящиеся к его строению. Абстракция является более общим термином. Она также может достигаться среди прочего с помощью подклассов. Например, класс List (список) в стандартной библиотеке является абстракцией для последовательности элементов, проиндексированных согласно их места в списке. Конкретными примерами списка List являются ArrayList или LinkedList . Код, который взаимодействует со списком List абстрагируется от деталей, какой именно список он использует. Часто абстракция невозможна без сокрытия основного состояния с помощью инкапсуляции. Если класс раскрывает свою внутреннюю структуру, он не может изменить свои внутренние операции, а, следовательно, не может абстрагироваться. Что такое абстрактный класс и абстрактный метод? Случается, что во время разработки вы хотите, чтобы базовый класс представлял только интерфейс для его производных классов. То есть вы не хотите, чтобы кто-либо создавал экземпляры базового класса. Вам необходимо использовать интерфейс таким образом, чтобы только приводить объекты к нему (это неявное приведение, которое обеспечивает полиморфное поведение). Это достигается путем создания данного класса абстрактным с помощью ключевого слова abstract . Это накладывает некоторые ограничения, такие как невозможность создавать экземпляры абстрактного класса, при использовании абстрактного класса необходимо реализовывать абстрактные методы. Этим обеспечивается полиморфизм. Абстрактный класс может содержать и абстрактные и конкретные методы. Если хоть один метод в классе объявлен абстрактным, весь класс должен так же быть объявлен абстрактным. Тем не менее, в обратную сторону правило не обязано соблюдаться. Если класс объявлен абстрактным, он может и не содержать абстрактные методы. Метод, который всего лишь определяет свои сигнатуры и не обеспечивает реализацию, называется абстрактным. Фактическая его реализация оставлена его подклассам, которые расширяют абстрактный класс. Абстрактный метод не может быть использован объектом, только другой класс может его расширить. Когда необходимо использовать абстрактный класс? Абстрактные классы позволяют вам определить некоторое поведение по умолчанию и заставить подклассы обеспечить любое конкретное поведение. Например: List (список) является интерфейсом, в свою очередь AbstractList определяет основное поведение Списка, которое может быть использовано как есть или уточнено в подклассе, например, в ArrayList (списочный массив). Что такое интерфейс? В концепции интерфейса лежит абстрактный класс, но интерфейс (определяется ключевым словом interface) шагнул дальше. Он предотвращает вообще любую реализацию метода или функции. Вы можете только объявлять метод или функцию, но не обеспечивать их реализацию. Класс, который реализует данный интерфейс, должен как раз и позаботиться о фактической реализации. Интерфейсы очень полезны и повсеместно используются в ООП. Так как они разделяют сам интерфей и реализацию, они предоставляют много преимуществ своего использования:
  1. Множественное наследование .
  2. Слабая связанность . Происходит абстракция операции, такая как разделение на уровни, а конкретной реализацией может быть что угодно: JDBC, JPA, JTA и т.д.
  3. Программа-интерфейс не реализуется .
  4. Полиморфизм с динамическим связыванием : раскрывается програмный интерфейс объекта без раскрытия его фактической реализации.
  5. Абстрактные уровни , разделение функциональностей.
Разница между интерфейсом и абстрактным классом.
  • Интерфейс - это договорные отношения с классами, которые этот интерфейс реализуют, о том, что реализация происходит путём, обозначенным интерфейсом. Это пустая оболочка с объявленными методами.
  • Абстрактный класс определяет некоторое общее поведение и просит свои подклассы определить нетипичное или конкретное поведение для своего класса.
  • Методы и члены абстрактного класса могут быть обозначены любым модификатором доступа, в свою очередь все методы интерфейса обязаны быть открытыми (public).
  • Когда происходит наследование абстрактного класса, класс-наследник должен определить абстрактные методы, в то время как интерфейс может наследовать другой интерфейс и при этом не обязательно определять его методы.
  • Класс-наследник может расширять только один абстрактный класс, а интерфейс может расширять или класс может реализовывать множество других интерфейсов.
  • Класс-наследник может определять абстрактные методы с тем же или менее ограниченным модификатором доступа, при этом класс, реализующий интерфейс, должен определять методы с тем же уровнем видимости.
  • Интерфейс не содержит конструкторы, в том время, как они есть в абстрактном классе.
  • Переменные, объявленные в Java-интерфейсе по умолчанию являются final. Абстрактный класс может содержать переменные, которые не являются final.
  • Все участники Java-интерфейса по умолчанию являются public . Участники абстрактного класса могут позволить себе быть public , protected и др.

Композиция

Повторное использование кода может быть достигнуто с помощью как наследования, так и композиции. Но при этом задействование композиции обеспечивает более высокий уровень инкапсуляции, чем наследование, так как изменения в back-end классе не обязательно затронут код, который относится к front-end классу. Композиция - это техника проектирования, применяющая в классах отношения типа “has-a” (имеет, включает в себя). Для повторного использования кода могут применяться как наследование в java, так и композиция объекта. Суть композиции заключается в выражении отношения "has a" между объектами. Подумайте о стуле. У стула есть (has a) сидение. У стула есть (has a) спинка. У стула есть (has a) определенное количество ножек. Фраза ”has a” / “есть” предполагает отношения, в которых стул имеет или, как минимум, использует другой объект. Это как раз и есть отношения “has-a”, являющиеся основой композиции. Преимущества:
  • Контроль видимости
  • Реализация может быть заменена во время выполнения (run-time)
  • Слабая связанность, так как класс-интерфейс не зависит от реализации.
Различия между композицией и наследованием
Композиция (has a / имеет) Наследование (is a / является)
1 Поддерживает полиморфизм и повторное использование кода.
2 Объект во время выполнения (run-time) уже создан. Объект создается динамически во время компиляции.
3 Реализация может быть заменена во время выполнения (run-time). Реализация может быть заменена во время компиляции.
4 Подкласс не зависит от класса-родителя, что благоприятствует слабому связыванию (особенно под управлением интерфейса). Подкласс завизист от реализации класса-родителя, поэтому связывание считается сильным.
5 Использование: в Доме есть Ванная комната. Неправильно говорить, что Дом - это Ванная комната. Наследование является однонаправленным: Дом - это Здание. Но здание не является домом.
Примечание: Не используйте наследование только для того, чтобы обеспечить повторное использование кода. Если нет отношенией “is a“ (является), для этих целей используется композиция. Разница между композицией и агрегацией в отношениях объектов. Агрегация - это взаимосвязь, при которой один класс вписывается в коллекцию. Это часть целого отношения, где часть может существовать без целого. Такие отношения гораздо слабее. Нет циклической зависимости. Например: заказ и продукт. Композиция - это взаимосвязь, при которой один класс вписывается в коллекцию. Это часть целого отношения, при которой часть не может существовать без целого. Если целое уничтожается, все его составляющие тоже будут уничтожены. Это более сильные отношения. Например: многоугольник и его вершины, заказ и его компонент.

Программирование - это процесс разработки решений «живых», динамичных задач в виде жёстких конструкций кода, данных, функций и алгоритмов. Процедура формирования строгого синтаксиса из неопределенной семантики. Реальные задачи - известная большая проблема алгоритмизации: чтобы достигнуть нужного решения, задачу нужно поместить в точные синтаксические конструкции.

ООП дважды делало попытку «сломать» эту древнюю концепцию программирования, но «оковы» классического стиля кодирования данных и алгоритмов все еще крепки.

Уровень и квалификация

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

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

Формы полиморфизма ООП, идеи инкапсуляции кода и наследование свойств (методов) лежат в сфере программирования, но никак не в сфере решаемой задачи.

Показательный пример - библиотека PHPOffice/PHPWord. Для её использования нужна квалификация разработчика, нужно создавать собственную систему объектов, но текущий уровень заказчика (требования заказчика) - это тривиальная композиция, которую программист перекрывает своей разработкой (иначе требования не удовлетворить). Ситуация вроде такой:

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

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

Полиморфизм и ООП

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

  • инкапсуляция;
  • полиморфизм;
  • наследование.

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

Итак, мнения об ООП полиморфны: описывают одно, сконструированы по-разному, или, наоборот, описывают разное, но базируются на четырех одинаковых позициях.

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

Популярные определения полиморфизма

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

  1. Полиморфизм в программировании - это способность предоставлять один и тот же интерфейс для различных базовых форм (типов данных).
  2. Полиморфизм - возможность объектов иметь различную реализацию.
  3. Полиморфизмом называется способность функции...
  4. Классика (от создателя С/С++): «один интерфейс - много реализаций».
  5. Параметрический полиморфизм подразумевает...
  6. Полиморфизм - положение теории типов...
  7. Абстракция невозможна без инкапсуляции и наследования, как невозможен полиморфизм без наследования...

Можно согласиться, что всё это относится к одному и тому же: но форма выражения мысли, сущность и содержание - не подобны. Но что-то общее всё же есть.

Сущность: разработчик - заказчик

Классическая разработка программ предполагает наличие программиста и задачи (клиент, заказчик). Программист исследует задачу, формализует её и делает код, который приводит к решению. Заказчик отрицает всё предложенное или только его часть, указывая на недоработки, и программист делает свою работу вновь.

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

  • компьютер не может сам решить задачу;
  • нужна программа, чтобы компьютер мог «понять» и «решить» задачу.

Задача - сфера компетенции заказчика, программа - это алгоритм «адаптации» задачи к возможностям компьютера - сфера компетенции программиста. Роль последнего заключается в «адаптации» компьютера к требованиям задачи, а это лишнее!

Предлагает абстрагироваться . Есть объекты - это сфера заказчика; есть реализация объектов - это сфера программиста. Никакой «технологической» связи между заказчиком и разработчиком. Идея кардинальная, не реализованная по сей день, но что-то уже стабильно работает.

Окна, кнопки и другие объекты

История the Air Art Technology, Object Magazine, Turbo Vision, Graph Vision - это уже история. Мало кто помнит эти реализации ООП, они практически не используются и забыты, но оконный интерфейс Windows знаком миллионам пользователей, а объекты в средах PHP, JavaScript и других языках интернет-технологий применяются сотнями тысяч разработчиков кода, о них знают миллионы посетителей веб-ресурсов.

Вероятно, это единственно правильный путь, по которому должно было развиваться ООП: инкапсуляция, наследование, полиморфизм для разработчика, но не для пользователя. Характерно, что именно эта позиция была основной при разработке визуального оформления (интерфейса) программного обеспечения Windows, прикладных программ типа Turbo Vision и Graph Vision.

Концепция, положенная в основу продуктов типа the Air Art Technology и Object Magazine, существенно отличалась. Здесь абстрактный объект был самым первым предком информационной структуры, инкапсулировал на абстрактном уровне код обработки информации. Объекты окон, кнопок, элементов визуального оформления здесь были вторичны.

В первом варианте (Windows & etc.) парадигма ООП: инкапсуляция, наследование, полиморфизм обозначалась на уровне абстрактного предка, а реализация кода формировалась на уровне каждого конкретного потомка по ветке наследования согласно нужным структуре и содержанию.

Во втором варианте (the Air Art Technology и Object Magazine) важен уровень абстрактного объекта. Что будет у конкретного потомка - не суть, главное, чтобы его ветка наследования удовлетворяла требованиям всех родителей вниз до корневой абстракции.

Объект и система объектов: алгоритм

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

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

Текущая практика относит понятие объекта к инструменту, то есть к языку программирования, интерфейсу, доступу к базе данных, соединению по сети, но нет ничего, что указывает на интересы заказчика, на решаемую задачу.

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

Программисты приняли ООП как средство для повышения качества и производительности своей работы, но не уступили ни капли «своей территории» заказчику. Основные понятия ООП - инкапсуляция, наследование, полиморфизм - остались в сфере разработки, а не трансплантировались в сферу задачи.

Объект и система объектов: задача и решение

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

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

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

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

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

Традиционное и объектное программирование

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

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

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

Списки и очереди преобразились, появилось понятие первого и последнего элемента массива, появились циклы «по каждому», а ссылочные варианты именования, использования и исполнения стали ещё более востребованными, чем раньше.

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

Что в основе: объект или система

Абстракция, как основное концептуальное положение ООП, вне зависимости от того, где находится зона ответственности (реализация) объекта - на уровне первого абстрактного объекта или на уровне конкретного потомка, - оставляет открытым вопрос: с чего всё начинать, с объекта или с системы?

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

Если в основу положить систему объектов, то получается система систем. Это трудно представить в отношении конкретной задачи, и с чего начинать разработку - тоже сложно понять. По большому счёту, полиморфизм ООП c его различиями в сущностях, формах реализации, количествах актуальных параметров в функциях даёт представление о системе, которая лежит в начале, как:

  • о вариантах решения задачи (например, меню);
  • о начальных условиях (применение задачи в разных условиях, данных);
  • о режимах работы (тестирование, настройка, работа).

Но это и подобное ему не даёт никаких оснований ставить в основу решения задачи систему объектов. Часто достаточно определить один единственный начальный объект.

История процесса решения задачи

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

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

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

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

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

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

Реальный полиморфизм ООП, пример

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

Не так давно была разработана библиотека PHPOffice/PHPWord, но для того чтобы использовать её возможности, практически всегда приходится создавать собственную систему объектов. Например, простой файл *.docx:

представляет собой zip-архив множества файлов и папок в формате Office Open XML (OpenXML, OOXML). Каждый файл записан в тегами XML, причём при добавлении, изменении и удалении букв, слов, таблиц, списков и пр. элементов содержимое файлов начинает представлять собой последовательность тегов, которые не всегда содержат полные элементы, часто один элемент записывается множеством тегов.

Если представить этот файл в виде последовательности тегов, получится интересная картинка:

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

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

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

Состояние области ООП

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

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

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

Перспективы объектной идеи

Сколько продержится классическое программирование и как будет развиваться ООП - сказать достаточно сложно. Судя по всему, разработчики инструментальных средств не планируют рассматривать контекст потребителя (пользователя, заказчика).

Инструментарий ООП - полиморфизм, наследование, инкапсуляция и абстракция - ориентируются на разработчика.

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

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

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

Кратко смысл полиморфизма можно выразить фразой: «Один интерфейс, множество реализаций».

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

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

внешняя общность проявляется как одинаковый набор методов с одинаковыми именами и сигнатурами (именем методов и типами аргументов и их количеством);

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

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

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

В объектно-ориентированных языках

В объектно-ориентированных языках класс является абстрактным типом данных.[Прим. 1] Полиморфизм реализуется с помощью наследования классов и виртуальных функций. Класс-потомок наследует сигнатуры методов класса-родителя, а реализация, в результате переопределения метода, этих методов может быть другой, соответствующей специфике класса-потомка. Другие функции могут работать с объектом как с экземпляром класса-родителя, но если при этом объект на самом деле является экземпляром класса-потомка, то во время исполнения будет вызван метод, переопределенный в классе-потомке. Это называется поздним связыванием. [Примером использования может служить обработка массива, содержащего экземпляры как класса-родителя, так и класса-потомка: очевидно, что такой массив может быть объявлен только как массив типа класса-родителя и у объектов массива могут вызываться только методы этого класса, но если в классе-потомке какие-то методы были переопределены, то в режиме исполнения для экземпляров этого класса будут вызваны именно они, а не методы класса-родителя.]

Класс-потомок сам может быть родителем. Это позволяет строить сложные схемы наследования - древовидные или сетевидные.

Абстрактные (или чисто виртуальные) методы не имеют реализации вообще (на самом деле некоторые языки, например C++, допускают реализацию абстрактных методов в родительском классе). Они специально предназначены для наследования. Их реализация должна быть определена в классах-потомках.

Класс может наследовать функциональность от нескольких классов. Это называется множественным наследованием. Множественное наследование создаёт известную проблему (в C++), когда класс наследуется от нескольких классов-посредников, которые в свою очередь наследуются от одного класса (так называемая «Проблема ромба»): если метод общего предка был переопределён в посредниках, неизвестно, какую реализацию метода должен наследовать общий потомок. Решается эта проблема путём отказа от множественного наследования для классов и разрешением множественного наследования для полностью абстрактных классов (то есть интерфейсов) (C#, Delphi, Java), либо через виртуальное наследование (C++).

В функциональных языках

Полиморфизм в функциональных языках будет рассмотрен на примере языка Haskell.

Лекция в виде презентации в формате pdf с примерами - 27 слайдов.
ВолгГТУ, кафедра ПОАС, - 2010 год

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

Фрагменты из лекции

Понятие полиморфизма

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

Преимущества использования полиморфизма

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

Параметризованный полиморфизм

  • Обеспечивается за счет так называемых обобщенных функций, которые в языке Си++ называются шаблонами
  • Аргументом обобщенной функции является тип, который используется при ее параметризации
  • С помощью механизма шаблонов можно создать функцию, которая бы работала с разнотипными аргументами
  • Примером таких функций являются обобщенные алгоритмы из STL

Чистый полиморфизм

  • Чистый полиморфизм имеет место, когда одна и та же функция применяется к аргументам различных типов
  • В случае чистого полиморфизма имеется одна функция (тело кода) и несколько ее интерпретаций
  • Реализация чистого полиморфизма возможна только при наличии полиморфных переменных, а точнее полиморфных аргументов
  • Чистый полиморфизм позволяет реализовывать обобщенные алгоритмы
Перегрузка или полиморфизм ad hoc
  • Перегрузка возникает, когда имеется два или более кода, связанных с одним именем
  • Главное назначение перегрузки − сужение концептуального пространства
Перегрузка методов в несвязанных классах
  • Все ОО-языки разрешают использовать методы с одинаковыми именами в несвязанных между собою классах − это перегрузка методов
  • В этом случае привязка перегруженного имени производится за счет информации о классе, к которому относится получатель сообщения

Параметрическая перегрузка

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

Class MyEllipse
{
public:
float area() const

};


{
public:
float area() const
{//использ. более эффективный алгоритм расчета
}
};

MyEllipse ellipse;
MyCircle circle;

// Будет вызван метод MyEllipse::area()
ellipse.print();


// ВНИМАНИЕ!!! Будет вызван метод MyEllipse::area()
circle.print();


Переопределение методов
  • При замещении метод базового класса перекрывается методом производного класса только снаружи. Внутри класса вызывается метод базового класса (см. предыдущий пример)
  • Переопределение метода возникает, когда метод производного класса подменяет метод базового класса не только снаружи, но и внутри класса
  • В языке Си++ для переопределения метода необходимо использовать механизм динамического связывания, т.е. объявить метод виртуальным
Пример переопределения метода

Class MyEllipse
{
public:
virtual float area() const
{ /* численный метод расчета */ }
void print() { printf("area = %f\n", area()); }
};
class MyCircle: public MyEllipse
{
public:
float area() const
{ //использ. более эффективн. алгоритм расчета
return 3.14*Radius1*Radius2;
}
};

MyEllipse ellipse;
MyCircle circle;

// Будет вызван метод MyEllipse::area()
printf("Ellipse area= %f\n", ellipse.area());

// Будет вызван метод MyEllipse::area()
ellipse.print();

// Будет вызван метод MyCircle::area()
printf("Circle area= %f\n", circle.area());

// ВНИМАНИЕ!!! Будет вызван метод MyCircle::area()
circle.print();

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

Отложенные методы

  • Отложенный метод − это частный случай переопределения, когда метод базового класса не имеет реализации, а любая полезная деятельность задается в методе дочернего класса
Отложенные методы в языке Си++
  • В языке Си++ отложенный метод должен быть описан в явном виде с ключевым словом virtual
  • Тело отложенного метода не определяется, вместо этого функции «приписывается» значение 0

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

Класс (java class) описывает устройство и поведение объектов. Устройство описывается через набор характеристик (свойств), а поведение – через набор доступных для объектов операций (методов). Классы можно создавать на основе уже имеющихся, добавляя или переопределяя свойства и методы.

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

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

Наследование является неотъемлемой частью Java. При использовании наследования принимается во внимание, что новый класс, наследующий свойства базового (родительского) класса имеет все те свойства, которым обладает родитель. В коде используется операнд extends , после которого указывается имя базового класса. Тем самым открывается доступ ко всем полям и методам базового класса.

Используя наследование, можно создать общий "java class", который определяет характеристики, общие для набора связанных элементов. Затем можно наследоваться от него и создать дополнительные классы, для которых определить дополнительные уникальные для них характеристики.

Главный наследуемый класс в Java называют суперклассом super . Наследующий класс называют подклассом . Таким образом подкласс - это специализированная версия суперкласса, которая наследует все свойства суперкласса и добавляет свои собственные уникальные элементы.

Рассмотрим пример описания java class"a студента Student, который имеет имя, фамилию, возраст, и номер группы. Класс студента будем создавать на основе super класса пользователя User, у которого уже определены имя, фамилия и возраст:

Public class User { int age; String firstName; String lastName; // Конструктор public User(int age, String firstName, String lastName) { this.age = age; this.firstName = firstName; this.lastName = lastName; } }

Теперь создаем отдельный класс Student, наследующего свойства super класса. При наследовании класса необходимо также переопределить и конструкторы родительского класса:

Public class Student extends User { int group; // Конструктор public Student(int age, String firstName, String lastName) { super(age, firstName, lastName); } boolean isMyGroup(int g) { return g == group; } }

Ключевое слово extends показывает, что мы наследуемся от класса User.

Ключевое слово super

В конструкторе класса Student мы вызываем конструктор родительского класса через оператор super , передавая ему весь необходимой набор параметров. В Java ключевое слово super обозначает суперкласс, т.е. класс, производным от которого является текущий класс. Ключевое слово super можно использовать для вызова конструктора суперкласса и для обращения к члену суперкласса, скрытому членом подкласса.

Рассмотрим как происходит наследование с точки зрения создания объекта:

Student student = new Student(18, "Киса", "Воробьянинов", 221);

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

У суперкласса могут быть несколько перегруженных версий конструкторов, поэтому можно вызывать метод super() с разными параметрами. Программа выполнит тот конструктор, который соответствует указанным аргументам.

Вторая форма ключевого слова super действует подобно ключевому слову this , только при этом мы всегда ссылаемся на суперкласс подкласса, в котором она использована. Общая форма имеет следующий вид:

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

Class A { int i; } // наследуемся от класса A class B extends A { int i; // имя переменной совпадает и скрывает переменную i в классе A B(int a, int b) { super.i = a; // обращаемся к переменной i из класса A i = b; // обращаемся к переменной i из класса B } void show() { System.out.println("i из суперкласса равно " + super.i); System.out.println("i в подклассе равно " + i); } } class MainActivity { B subClass = new B(1, 2); subClass.show(); }

В результате в консоли мы должны увидеть:

I из суперкласса равно 1 i в подклассе равно 2

Переопределение методов, Override

Если в иерархии классов имя и сигнатура типа метода подкласса совпадает с атрибутами метода суперкласса, то метод подкласса переопределяет метод суперкласса. Когда переопределённый метод вызывается из своего подкласса, он всегда будет ссылаться на версию этого метода, определённую подклассом. А версия метода из суперкласса будет скрыта.

Если нужно получить доступ к версии переопределённого метода, определённого в суперклассе, то необходимо использовать ключевое слово super .

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

В Java SE5 появилась анотация @Override; . Если необходимо переопределить метод, то используйте @Override, и компилятор выдаст сообщение об ошибке, если вместо переопределения будет случайно выполнена перегрузка.

В Java можно наследоваться только от одного класса.

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

В информатике инкапсуляцией (лат. en capsula) называется упаковка данных и/или функций в единый объект.

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

Модификаторы доступа

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

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

Желательно использовать доступ к свойствам класса только через его методы (принцип bean классов, "POJO"), который позволяет валидировать значения полей, так как прямое обращение к свойствам отслеживать крайне сложно, а значит им могут присваиваться некорректные значения на этапе выполнения программы. Такой принцип относится к управлению инкапсулированными данными и позволяет быстро изменить способ хранения данных. Если данные станут храниться не в памяти, а в файлах или базе данных, то потребуется изменить лишь ряд методов одного класса, а не вводить эту функциональность во все части системы.

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

Пример простого описания робота

Public class Robot { private double x = 0; // Текущая координата X private double y = 0; // Текущая координата Y private double course = 0; // Текущий курс (в градусах) public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } public double getCourse() { return course; } // Определение курса public void setCourse(double course) { this.course = course; } // Передвижение на дистанцию distance public void forward(int distance) { // Обращение к полю объекта X x = x + distance * Math.cos(course / 180 * Math.PI); // Обращение к полю объекта Y y = y + distance * Math.sin(course / 180 * Math.PI); } // Печать координат робота public void printCoordinates() { System.out.println(x + "," + y); } }

В представленном примере робота используются наборы методов, начинающие с set и get . Эту пару методов часто называют сеттер/геттер. Данные методы используются для доступа к полям объекта. Наименования метода заканчиваются наименованием поля, начинающееся с ПРОПИСНОЙ буквы.

В методах set мы передаем значение через формальный параметр во внутрь процедуры. В коде процедуры мы присваиваем значение переменной объекта/класса с использованием ключевого слова this .

This.course = course ...

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

Полиморфизм, polymorphism

Полиморфизм является одним из фундаментальных понятий в объектно-ориентированном программировании наряду с наследованием и инкапсуляцией. Слово полиморфизм греческого происхождения и означает "имеющий много форм". Чтобы понять, что означает полиморфизм применительно к объектно-ориентированному программированию, рассмотрим пример создания векторного графического редактора, в котором необходимо использовать ряд классов в виде набора графических примитивов - Square , Line , Circle , Triangle , и т.д. У каждого из этих классов необходимо определить метод draw для отображения соответствующего примитива на экране.

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

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

// Определение массивов графических примитивов Square s = new Square ; Line l = new Line ; Circle c = new Circle ; Triangle t = new Triangle; // Заполнение всех массивов соответствующими объектами. . . // Цикл с перебором всех ячеек массива. for (int i = 0; i < s.length; i++){ // вызов метода draw() в случае, если ячейка не пустая. if (s[i] != null) s.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 < t.length; i++){ if (t[i] != null) t.draw(); }

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

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

Public class Shape { public void draw() { System.out.println("Заглушка"); } }

После этого мы создаем различные классы-наследники: Square (Квадрат), Line (Линия), Сircle (круг) и Triangle (Треугольник):

Public class Point extends Shape { public void draw() { System.out.println("Квадрат"); } } public class Line extends Shape { public void draw() { System.out.println("Линия"); } } public class Сircle extends Shape { public void draw() { System.out.println("Круг"); } } public class Triangle extends Shape { public void draw() { System.out.println("Треугольник"); } }

В наследниках у нас переопределен метод draw. В результате получили иерархию классов, которая изображена на рисунке.

Теперь проверим удивительную возможность полиморфизма:

// Определение и инициализация массива Shape a = new Shape {new Shape(), new Triangle(), new Square(), new Сircle()}; // Перебор в цикле элементов массива for(int i = 0; i < a.length; i++) { a[i].draw(); }

В консоль будут выведены следующие строки:

Заглушка Треугольник Квадрат Круг

Таким образом каждый класс-наследник вызвал именно свой метод draw, вместо того, чтобы вызвать метод draw из родительского класса Shape.

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

Перегрузка метода, overload

В процедурном программировании тоже существует понятие полиморфизма, которое отличается от рассмотренного механизма в ООП. Процедурный полиморфизм предполагает возможность создания нескольких процедур или функций с одинаковым именем, но разными количеством или типами передаваемых параметров. Такие одноименные функции называются перегруженными, а само явление - перегрузкой (overload). Перегрузка функций существует и в ООП и называется перегрузкой методов. Примером использования перегрузки методов в языке Java может служить класс PrintWriter , который используется в частности для вывода сообщений на консоль. Этот класс имеет множество методов println, которые различаются типами и/или количеством входных параметров. Вот лишь несколько из них:

Void println() // переход на новую строку void println(boolean x) // выводит значение булевской переменной (true или false) void println(String x) // выводит строку - значение текстового параметра

© 2024 Windows. Инструкции. Программы. Железо. Ошибки