Объектно ориентированное программирование три кита

Концепция объектно-ориентированного программирования

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

Давайте предположим, что перед нами поставили задачу создать простой графический редактор, в котором пользователь может рисовать графические примитивы: линию, треугольник, прямоугольник и эллипс:

Если бы в Java не было классов, то нам пришлось бы хранить фигуры в памяти устройства в виде набора координат вершин:

int N = 0; int points_x[] = new int[100]; int points_y[] = new int[100]; // треугольник points_x[0] = 10; points_y[0] = 5; points_x[1] = 20; points_y[1] = 10; points_x[2] = 5; points_y[2] = 10; // линия points_x[3] = 100; points_y[3] = 100; points_x[4] = 200; points_y[4] = 50; N = 5; // число вершин

Затем, например, для перемещения треугольника, нужно было бы сначала найти его вершины и только потом изменить его координаты. То же самое при изменении стиля линии: толщины и цвета. Если бы современный инструментарий программиста ограничивался бы только переменными и массивами, то лично я никогда бы не захотел быть программистом. Написание масштабных приложений превратилось бы в пытку. Но как тогда можно упростить программирование нашего примера? Вот здесь существенную помощью оказывает ООП. Давайте посмотрим, как все поменяется в сравнении с представлением на уровне массива.

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

class Triangle { int x1, x2, x3; int y1, y2, y3; int width, color; }

Здесь за ключевым словом class идет имя формируемого класса – Triangle (треугольник), а внутри (в фигурных скобках) – набор необходимых переменных (их еще принято называть полями класса, членами класса или просто – переменными класса). То есть, мы создали общее описание треугольника в виде трех вершин, толщины линии и цвета линии. Но вы можете заметить, что класс у нас один, а треугольников может быть множество. Все верно. Дело в том, что класс следует воспринимать как некий шаблон, чертеж, проект, по которому, затем, можно сформировать любое количество конкретных объектов:

Triangle t1 = new Triangle(); Triangle t2 = new Triangle(); Triangle t3 = new Triangle();

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

По аналогии мы можем объявить еще три класса с именами:

class Line {} class Rectangle {} class Ellipse {}

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

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

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

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

DRY – Don’t Repeat Yourself

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

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

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

Следующий кит ООП носит «умное» название – инкапсуляция. Но за этим умным словом скрывается очень простая идея: возможность скрывать внутри класса его элементы, чаще всего – это переменные (поля) и функции (методы). Давайте конкретизируем этот момент. Предположим, в классе Triangle имеется еще одна переменная id – идентификатор объекта. Это значение формируется в момент создания объекта и не должно в последствии меняться. Для этого это поле id можно указать скрытым и тогда доступ к нему извне класса будет невозможен:

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

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

Полиморфизм

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

В рамках ООП полиморфизм часто проявляется в переопределении методов базового класса. Например, в рамках нашего графического редактора в базовом классе Properties можно определить метод draw(), который будет отвечать за рисование графических примитивов. Затем, этот метод переопределить в дочерних классах и тогда, вызывая draw() по ссылке на базовый класс, будет вызываться переопределенный метод дочернего класса:

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

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

И популярность этого подхода не случайна. Он существенно упрощает проектирование и разработку больших приложений. А объектами могут быть самые разные элементы программы. Фактически, класс – это фрагмент программы, который можно многократно использовать и частично модифицировать под свои конкретные нужды. На этом принципе основаны многочисленные библиотеки: начиная от обычных, вычислительных, и заканчивая графическими и игровыми движками. Без ООП современная разработка больших программ была бы куда сложнее и запутаннее. И, конечно, далее на наших занятиях мы поближе познакомимся с миром классов и объектов на примере языка Java.

Видео по теме

#11 Концепция объектно-ориентированного программирования (ООП)

Источник

Три кита ООП — Наследование, инкапсуляция, полиморфизм

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

class Animal
function draw
return «just animal» ;

function eat
return «the animal is eating» ;

class Cow extends Animal
function draw
Return «something that looks like a cow» ;

Как видите здесь Корова (Cow) унаследовала функционал от Животного (Animal), изменив реализацию метода draw (конкретизируя как корова на самом деле выглядит), и оставив реализацию метода eat(). Это и есть наследование.

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

function __construct$name
$this -> name = $name ;

function getName
return $this -> name ;

Вот это и есть инкапсуляция. Нет способа изменить кличку снаружи класса, и вы можете быть уверены, что в любом случае, кличка у экземпляра класса будет именно та, что была задана при создании. Ну а теперь полиморфизм. Это тут тоже начнем с примера. Добавим класс Sheep (овца).

class Sheep extends Animal

function draw
return ‘something that looks like a sheep’ ;

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

Данный пример будет случайным образом генерировать экземпляр Коровы и Овцы, и рисовать их. Нужно сказать что данный пример не совсем «чистый» полиморфизм. Дело в том что полиморфизм подразумевает собой реализацию одного и того же интерфейса в разных классах. Объясню: если бы мы не реализовали метод draw() в одном из классов, у нас переодически возникала бы ошибка обращения к несуществующему методу, а в языках со строгой типизицией, ошибка бы возникала еще на стадии компиляции. Чтобы избежать подобных казусов, нужно использовать итерфейсы (interface):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

class Cow extends Animal implements IDrawable

function draw
return ‘something that looks like a cow’ ;

class Sheep extends Animal implements IDrawable

function draw
return ‘something that looks like a sheep’ ;

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

Источник

Формула объекта. Три кита ооп

Авторы надеются, что читатель помнит кое-что из главы 2 и такие понятия как тип данных, процедура, функция, запись для него не в новинку. Это прекрасно. Так вот, в конце 60-х годов кому-то пришло в голову объединить эти понятия, и то, что получилось, назвать объектом. Рассмотрение данных в неразрывной связи с методами их обработки позволило вывести формулу объекта: Объект = Данные + Операции На основании этой формулы была разработана методология объектно-ориентированного программирования (ООП).

3.1.5. Три кита ооп

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

Источник

Читайте также:  Пейтон язык программирования обучение
Оцените статью