Понимание ооп. Основные принципы ооп

05.08.2019

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

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

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


Об объектах и классах

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

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

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

/** * Класс Треугольник. */ class Triangle { /** * Специальный метод, называемый конструктор класса. * Принимает на вход три параметра: * длина стороны А, длина стороны Б, * угол между этими сторонами(в градусах) */ Triangle(double sideA, double sideB, double angleAB) { this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; } double sideA; //Поле класса, хранит значение стороны А в описываемом треугольнике double sideB; //Поле класса, хранит значение стороны Б в описываемом треугольнике double angleAB; //Поле класса, хранит угла(в градусах) между двумя сторонами в описываемом треугольнике /** * Метод класса, который рассчитывает площадь треугольника */ double getSquare() { double square = this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180); return square; } /** * Метод класса, который рассчитывает периметр треугольника */ double getPerimeter() { double sideC = Math.sqrt(Math.pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this.angleAB * Math.PI / 180)); double perimeter = this.sideA + this.sideB + sideC; return perimeter; } }

Если мы внутрь класса добавим следующий код:

/** * Именно в этом месте запускается программа */ public static void main(String args) { //Значения 5, 17, 35 попадают в конструктор класса Triangle Triangle triangle1 = new Triangle(5, 17, 35); System.out.println("Площадь треугольника1: "+triangle1.getSquare()); System.out.println("Периметр треугольника1: "+triangle1.getPerimeter()); //Значения 6, 8, 60 попадают в конструктор класса Triangle Triangle triangle2 = new Triangle(6, 8, 60); System.out.println("Площадь треугольника1: "+triangle2.getSquare()); System.out.println("Периметр треугольника1: "+triangle2.getPerimeter()); }

то программу уже можно будет запускать на выполнение. Это особенность языка java. Если в классе есть такой метод

Public static void main(String args)

то этот класс можно выполнять. Разберем код подробнее. Начнем со строки

Triangle triangle1 = new Triangle(5, 17, 35);

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

System.out.println("Площадь треугольника1: "+triangle1.getSquare()); System.out.println("Периметр треугольника1: "+triangle1.getPerimeter());

выводят рассчитанные площадь треугольника и его периметр в консоль.

Аналогично все происходит и для второго экземпляра класса Triangle .

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

Еще раз, самое важное:

ООП - это способ организации кода программы;

Класс - это пользовательская структура данных, которая воедино объединяет данные и функции для работы с ними(поля класса и методы класса);

Объект - это конкретный экземпляр класса, полям которого заданы конкретные значения.


Три волшебных слова

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

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

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

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

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


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

/** * Класс точки. Базовый класс */ class Point { /** * Пустой конструктор */ Point() {} /** * Метод класса, который рассчитывает площадь фигуры */ double getSquare() { return 0; } /** * Метод класса, который рассчитывает периметр фигуры */ double getPerimeter() { return 0; } /** * Метод класса, возвращающий описание фигуры */ String getDescription() { return "Точка"; } }

У получившегося класса Point пустой конструктор, поскольку в данном примере мы работаем без конкретных координат, а оперируем только параметрами значениями сторон. Так как у точки нет никаких сторон, то и передавать ей никаких параметров не надо. Также заметим, что класс имеет методы Point::getSquare() и Point::getPerimeter() для расчета площади и периметра, оба возвращают 0. Для точки оно и логично.


Поскольку у нас точка является основой всех прочих фигур, то и классы этих прочих фигур мы наследуем от класса Point . Опишем класс отрезка, наследуемого от класса точки:

/** * Класс Отрезок */ class LineSegment extends Point { LineSegment(double segmentLength) { this.segmentLength = segmentLength; } double segmentLength; // Длина отрезка /** * Переопределенный метод класса, который рассчитывает площадь отрезка */ double getSquare() { return 0; } /** * Переопределенный метод класса, который рассчитывает периметр отрезка */ double getPerimeter() { return this.segmentLength; } String getDescription() { return "Отрезок длиной: " + this.segmentLength; } }

Class LineSegment extends Point

означает, что класс LineSegment наследуется от класса Point . Методы LineSegment::getSquare() и LineSegment::getPerimeter() переопределяют соответствующие методы базового класса. Площадь отрезка всегда равняется нулю, а площадь периметра равняется длине этого отрезка.

Теперь, подобно классу отрезка, опишем класс треугольника(который также наследуется от класса точки):

/** * Класс Треугольник. */ class Triangle extends Point { /** * Конструктор класса. Принимает на вход три параметра: * длина стороны А, длина стороны Б, * угол между этими сторонами(в градусах) */ Triangle(double sideA, double sideB, double angleAB) { this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; } double sideA; //Поле класса, хранит значение стороны А в описываемом треугольнике double sideB; //Поле класса, хранит значение стороны Б в описываемом треугольнике double angleAB; //Поле класса, хранит угла(в градусах) между двумя сторонами в описываемом треугольнике /** * Метод класса, который рассчитывает площадь треугольника */ double getSquare() { double square = (this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180))/2; return square; } /** * Метод класса, который рассчитывает периметр треугольника */ double getPerimeter() { double sideC = Math.sqrt(Math.pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this.angleAB * Math.PI / 180)); double perimeter = this.sideA + this.sideB + sideC; return perimeter; } String getDescription() { return "Треугольник со сторонами: " + this.sideA + ", " + this.sideB + " и углом между ними: " + this.angleAB; } }

Тут нет ничего нового. Также, методы Triangle::getSquare() и Triangle::getPerimeter() переопределяют соответствующие методы базового класса.
Ну а теперь, собственно, тот самый код, который показывает волшебство полиморифзма и раскрывает мощь ООП:

Class Main { /** * Именно в этом месте запускается программа */ public static void main(String args) { //ArrayList - Это специальная структура данных в java, // позволяющая хранить объекты определенного типа в массиве. ArrayList figures = new ArrayList(); //добавляем три разных объекта в массив figures figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); for (int i = 0; i

Мы создали массив объектов класса Point , а поскольку классы LineSegment и Triangle наследуются от класса Point , то и их мы можем помещать в этот массив. Получается, каждую фигуру, которая есть в массиве figures мы можем рассматривать как объект класса Point . В этом и заключается полиморфизм: неизвестно, к какому именно классу принадлежат находящиеся в массиве figures объекты, но поскольку все объекты внутри этого массива принадлежат одному базовому классу Point , то все методы, которые применимы к классу Point также и применимы к его классам-наследникам.


Теперь о инкапсуляции. То, что мы поместили в одном классе параметры фигуры и методы расчета площади и периметра - это и есть инкапсуляция, мы инкапсулировали фигуры в отдельные классы. То, что у нас для расчета периметра используется специальный метод в классе - это и есть инкапсуляцию, мы инкапсулировали расчет периметра в метод getPerimiter() . Иначе говоря, инкапсуляция - это сокрытие реализции (пожалуй, самое короткое, и в то же время емкое определением инкапсуляции).


Полный код примера:

Import java.util.ArrayList; class Main { /** * Именно в этом месте запускается программа */ public static void main(String args) { //ArrayList - Это специальная структура данных в java, // позволяющая хранить объекты определенного типа в массиве. ArrayList figures = new ArrayList(); //добавляем три разных объекта в массив figures figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); for (int i = 0; i

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

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

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

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

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

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

Преимущества ООП

Особенности объектно-ориентированного программирования наделяют его рядом преимуществ.

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

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

Недостатки ООП

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

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

Особенности ООП в Python

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

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

В Python нет просто типов данных. Все типы – это классы.

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

И напоследок

Python – это все-таки скриптовый интерпретируемый язык. Хотя на нем пишутся в том числе крупные проекты, часто он используется в веб-разработке, системном администрировании для создания небольших программ-сценариев. В этом случае обычно достаточно встроенных средств языка, "изобретать" собственные классы излишне.

(как расшифровывается ООП) – это, прежде всего, парадигма программирования.
Парадигма программирования определяет то, как программист видит выполнение программы.
Так, для парадигмы ООП характерно, что программист рассматривает программу в виде набора взаимодействующих объектов, в то время как, например, в функциональном программировании программа представляется в виде последовательности вычисления функций. Процедурное программирование или, как его еще правильно называют, классическое операциональное, подразумевает написание алгоритма для решения задачи; при этом ожидаемые свойства конечного результата не описываются и не указываются. Структурное программирование в основном придерживается тех же принципов, что и процедурное, лишь немного дополняя их полезными приемами.
Парадигмы непроцедурного программирования, к которым можно отнести объектно-ориентированную парадигму, имеют совершенно другие идеи.
Определение Гради Буча гласит: “Объектно-ориентированное программирование – это методология программирования, которая основана на представлении программы в виде совокупности объектов, каждый из которых является реализацией определенного класса (типа особого вида), а классы образуют иерархию на принципах наследуемости”.
Структурное и объектно-ориентированное программирование строятся на таком научном методе как декомпозиция — метод, который использует структуру задачи и позволяет разбить решение общей большой задачи на решение последовательности меньших задач. Декомпозиция ООП происходит не по алгоритмам, а по объектам, использующимся при решении задачи. Данная декомпозиция уменьшает размер программных систем благодаря повторному использованию общих механизмов. Известно, что системы визуального программирования или системы, построенные на принципах объектно-ориентированного программирования, являются более гибкими и легче эволюционируют со временем.

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

Сегодня существует достаточное количество объектно-ориентированных языков программирования , наиболее популярными из которых в настоящее время являются C++, Delphi, Java, Visual Basic, Flash. Но, кроме того, многие языки, которые принято причислять к процедурной парадигме, тоже обладают свойствами ООП, имея возможность работать с объектами. Так, объектно-ориентированное программирование в C — это большой раздел программирования на данном языке, то же самое касается ООП в python и многих других структурных языках.

Говоря об ООП, часто всплывает еще одно определение — визуальное программирование . Оно дополнительно предоставляет широкие возможности использования прототипов объектов, которые определяются как классы объектов.
События. Во многих средах визуального программирования реализована характеристика (помимо инкапсуляции, полиморфизма и наследования) объекта – событие. Событиями в объектно-ориентированном программировании называется возможность обработки так называемых сообщений (или событий), получаемых от операционной системы Windows или самой программы. Данный принцип характерен для всех компонентов среды, которые обрабатывают различные события, возникающие в процессе выполнения программы. По сути, событие — это некоторое действие, которое активизирует стандартную реакцию объекта. Событием может рассматриваться, например, щелчок по кнопке мыши, наведение курсора мыши на пункт меню, открытие вкладки и т.п. Очередность выполнения тех или иных действий определяется как раз таки событиями, возникающими в системе, и реакцией на них объектов.
Классы и объекты в ООП — различные понятия. Понятие класса в ООП – это тип данных (такой же как, например, Real или String), а объект – конкретный экземпляр класса (его копия), хранящийся в памяти компьютера как переменная соответствующего типа.
Класс является структурным типом данных. Класс включает описание полей данных, а также процедур и функций, которые работают с этими полями данных. Метод ООП – это и есть такие процедуры и функции применительно к классам.
Классы имеют поля (как тип данных запись — record), свойства, которые похожи на поля, но имеют дополнительные описатели, определяющие механизмы записи и считывания данных и методы — подпрограммы, которые направленны на изменение полей и свойств класса.

Основные принципы ООП

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

Принцип наследования ООП и подклассы

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

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

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

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

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

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

Процедурные языки

C, Pascal, FORTRAN и подобные языки являются процедурными. То есть каждый их оператор приказывает компьютеру что-то сделать: получить данные, сложить числа, разделить на шесть, отобразить результат. Приложение на процедурном языке представляет собой список инструкций. Если он небольшой, никакого другого организационного принципа (часто называемого парадигмой) не требуется. Программист создает список инструкций, и компьютер выполняет их.

Разделение на функции

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

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

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

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

Проблемы структурного программирования

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

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

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

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

Неограниченный доступ

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

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

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

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

Например, в программе учета кто-то решит, что код учитываемого предмета должен состоять не из 5 цифр, а из 12. Это потребует изменить с short на long. Теперь связанные с кодом функции должны быть изменены для работы с новым форматом.

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

Моделирование реального мира

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

Атрибуты

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

Поведение

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

Решение проблемы

Объект в ООП представляется как совокупность данных и функций. Только процедуры, которые называются функциями-членами в C ++, позволяют получить его значения. Данные скрыты и защищены от изменения. Значения и функции инкапсулированы в одно целое. Инкапсуляция и упрятывание - основные термины в описании ОО-языков.

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

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

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

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

Аналогия

Можно представить объекты отделами компании. В большинстве организаций сотрудники не работают один день с кадрами, на следующий начисляя зарплату, а затем неделю занимаясь розничной торговлей. У каждого отдела есть свой персонал с четко возложенными на него обязанностями. Есть и собственные данные: показатели заработной платы, продаж, учет сотрудников и т. д. Люди в отделах работают со своей информацией. Разделение компании, таким образом, облегчает контроль за ее деятельностью и поддерживает целостность данных. Бухгалтерия отвечает за Если необходимо знать общую сумму заработной платы, выплачиваемой в южном филиале в июле, не нужно рыться в архиве. Достаточно направить записку ответственному лицу, подождать, пока этот человек получит доступ к данным и отправит ответ с требуемой информацией. Это гарантирует соответствие регламенту и отсутствие постороннего вмешательства. Таким же образом объект в ООП обеспечивает организацию приложения.

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

Объект в ООП: определение

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

Какие вещи становятся объектами в ООП? Ниже представлены типичные категории.

Физический объект в ООП - это:

  • транспорт в моделях движения потока;
  • электрические элементы в программах схемотехники;
  • страны в модели экономики;
  • самолет в системе управления воздушным движением.

Элементы среды компьютера пользователя:

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

Связь объектов реального мира и ООП стало результатом сочетания функций и данных: они произвели переворот в программировании. Такого близкого соответствия в процедурных языках нет.

Класс

Объекты в ООП - это члены классов. Что это значит? Языки программирования имеют встроенные типы данных. Тип int, т. е. целое число, предопределен в C++. Можно объявлять сколько угодно переменных int.

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

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

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

В жизни классы разделены на подклассы. Например, животные делятся на земноводных, млекопитающих, птиц, насекомых и т. д.

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

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

Повторное использование

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

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

Создание новых типов данных

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

position1 = position + origin,

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

Полиморфизм, перегрузка

Операторы = (равно) и + (плюс), используемые в позиционной арифметике выше, не действуют так же, как с встроенными типами, такими как int. Объекты position и др. не предопределены, а заданы программным путем. Каким образом эти операторы знают, как с ними обращаться? Ответ заключается в том, что для них можно задать новые модели поведения. Эти операции будут функциями-членами класса Position.

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

Книга об ООП «Объектно-ориентированное программирование для чайников» позволит всем желающим ознакомиться с данной темой подробнее.

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

  • Инкапсуляция . Как данный язык скрывает внутренние особенности реализации объекта?
  • Наследование . Как данный язык обеспечивает возможность многократного использования программного кода?
  • Полиморфизм . Как данный язык позволяет интерпретировать родственные объекты унифицированным образом?

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

Одним из важных аспектов инкапсуляции является защита данных. В идеале данные, характеризующие состояние объекта, должны определяться, как закрытые и недоступные для внешнего окружения. В этом случае внешнее окружение объекта будет вынуждено запрашивать право на изменение или чтение соответствующих значений. Таким образом, понятие инкапсуляции отражает общее правило, согласно которому поля данных объекта не должны быть непосредственно доступны из открытого интерфейса. Если пользователю необходимо изменить состояние объекта, то он должен сделать это не напрямую, а косвенно, с помощью функций чтения (get ()) и модификации (set ()). В С# доступность данных реализуется на уровне синтаксиса с помощью ключевых слов public , private , protected , и protected internal .

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

Следующим принципом ООП является наследование , означающее способность языка обеспечить построение определений новых классов на основе определений уже существующих классов. В сущности, наследование позволяет расширить возможности поведения базового класса (называемого также родительским классом ) с помощью построения подкласса (называемого производным или дочерним классом ), наследующего характеристики и функциональные возможности родительского класса. По сути дела такая форма наследования представляет собой повторное использование программного кода одного (базового) класса в других (производных от него) классах. Как правило, в этом случае дочерний класс расширяет возможности базового класса, добавляя к ним некоторые новые возможности, отсутствующие в базовом классе. Такая форма наследования получила название "is-a" (т.е. быть тем же самым, но с более широкими возможностями).


Существует и другая форма многократного использования программного кода – это модель локализации/делегирования (также известная, как отношение локализации "has-a"). Эта форма не используется для создания отношений "класс-подкласс". Вместо этого класс может определить в своем составе некоторую переменную другого класса и открыть часть или все ее функциональные возможности для внешнего окружения. В этом случае класс больше похож на контейнер, в котором содержатся экземпляры других классов.

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