Что такое инкапсуляция в программировании
Перейти к содержимому

Что такое инкапсуляция в программировании

  • автор:

Инкапсуляция (программирование)

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

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

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

Сокрытие реализации целесообразно применять в следующих целях:

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

Примеры

C++

class A  public: int a, b; //данные открытого интерфейса int ReturnSomething(); //метод открытого интерфейса private: int Aa, Ab; //скрытые данные void DoSomething(); //скрытый метод >; 

Класс А инкапсулирует свойства Aa, Ab и метод DoSomething, представляя внешний интерфейс ReturnSomething, a, b.

C#

Целью инкапсуляции является обеспечение согласованности внутреннего состояния объекта. В C# для инкапсуляции используются публичные свойства и методы объекта. Переменные, за редким исключением, не должны быть публично доступными. Проиллюстрировать инкапсуляцию можно на простом примере. Допустим, нам необходимо хранить вещественное значение и его строковое представление (например, для того, чтобы не производить каждый раз конвертацию в случае частого использования). Пример реализации без инкапсуляции таков:

class NoEncapsulation  public double Value; public string ValueString; > 

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

class EncapsulationExample  private double valueDouble; private string valueString; public double Value  get  return valueDouble; > set  valueDouble = value; valueString = value.ToString(); > > public string ValueString  get  return valueString; > set  double tmp_value = Convert.ToDouble(ValueString); //здесь может возникнуть исключение valueDouble = tmp_value; valueString = ValueString; > > > 

Здесь доступ к переменным valueDouble и valueString возможен только через свойства Value и ValueString. Если мы попытаемся присвоить свойству ValueString некорректную строку и возникнет исключение в момент конвертации, то внутренние переменные останутся в прежнем, согласованном состоянии, поскольку исключение вызывает выход из процедуры.

Delphi

В Delphi для создания скрытых полей или методов их достаточно объявить в секции private .

TMyClass = class private FMyField: Integer; procedure SetMyField(const Value: Integer); function GetMyField: Integer; protected public property MyField: Integer read GetMyField write SetMyField; end; 

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

PHP5

class A  private $a; // скрытое свойство private $b; // скрытое свойство private function DoSomething() //скрытый метод  //actions > public function ReturnSomething() //открытый интерфейс  //actions > >; 

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

Java

class A  private int a; private int b; private void doSomething()  //скрытый метод //actions > public int returnSomething()  //открытый метод return a; > > 

JavaScript

A = function()  // private var _property; var _privateMethod = function()  /* actions */ > // скрытый метод // public this.getProperty = function()  // открытый интерфейс return _property; > this.setProperty = function(value)  // открытый интерфейс _property = value; _privateMethod(); > > 

См. также

  • Абстракция данных
  • Полиморфизм (программирование)
  • Наследование (программирование)
  • Инкапсуляция (программирование)

Wikimedia Foundation . 2010 .

  • Декомпрессионная болезнь
  • Трёхчленные гетероциклы

Полезное

Смотреть что такое «Инкапсуляция (программирование)» в других словарях:

  • Инкапсуляция — (лат. in в, capsula коробочка ; итал. incapsulare закупоривать) 1. Изоляция, закрытие чего либо мешающего, ненужного, вредного с целью исключения отрицательного влияния на окружающее. (Поместить радиоактивные отходы в капсулу, закрыть… … Википедия
  • Инкапсуляция — в объектно ориентированном программировании сокрытие внутренней структуры данных и реализации методов объекта от остальной программы. Другим объектам доступен только интерфейс объекта, через который осуществляется все взаимодействие с ним. По… … Финансовый словарь
  • Инкапсуляция (в объектно-ориентированном программировании) — Инкапсуляция свойство языка программирования, позволяющее объединить данные и код в объект и скрыть реализацию объекта от пользователя. При этом пользователю предоставляется только спецификация (интерфейс) объекта. Пользователь может… … Википедия
  • Интерфейс (объектно-ориентированное программирование) — У этого термина существуют и другие значения, см. Интерфейс (значения). Интерфейс (от лат. inter «между», и face «поверхность») семантическая и синтаксическая конструкция в коде программы, используемая для специфицирования… … Википедия
  • Полиморфизм (программирование) — У этого термина существуют и другие значения, см. Полиморфизм. Эта статья или раздел нуждается в переработке. Пожалуйста, улучшите статью … Википедия
  • Контейнер (программирование) — У этого термина существуют и другие значения, см. Контейнер. Контейнер в программировании структура (АТД), позволяющая инкапсулировать в себя объекты разных типов. Среди «широких масс» программистов наиболее известны контейнеры, построенные … Википедия
  • Уровень абстракции (программирование) — У этого термина существуют и другие значения, см. Абстракция (значения). Типичное представление архитектуры компьютера в … Википедия
  • Объектно-ориентированное программирование — Эта статья во многом или полностью опирается на неавторитетные источники. Информация из таких источников не соответствует требованию проверяемости представленной информации, и такие ссылки не показывают значимость темы статьи. Статью можно… … Википедия
  • Объектно-ориентированное программирование на Python — Объектно ориентированное программирование на Python программирование на Python с использованием парадигмы ООП: с самого начала Python проектировался как объектно ориентированный язык программирования[1]. Содержание 1 Введение 1.1 … Википедия
  • Объектно-ориентированное программирование на Питоне — С самого начала Питон проектировался как объектно ориентированный язык программирования [1]. Содержание 1 Введение 1.1 Принципы ООП … Википедия
  • Обратная связь: Техподдержка, Реклама на сайте
  • �� Путешествия

Экспорт словарей на сайты, сделанные на PHP,
WordPress, MODx.

  • Пометить текст и поделитьсяИскать в этом же словареИскать синонимы
  • Искать во всех словарях
  • Искать в переводах
  • Искать в ИнтернетеИскать в этой же категории

ООП для новичков: инкапсуляция, наследование и полиморфизм

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

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

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

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

Что делаем

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

Исходный код

# подключаем графическую библиотеку from tkinter import * # подключаем модули, которые отвечают за время и случайные числа import time # создаём новый объект — окно с игровым полем. В нашем случае переменная окна называется tk, и мы его сделали из класса Tk() — он есть в графической библиотеке tk = Tk() # делаем заголовок окна — Games с помощью свойства объекта title tk.title('Разбираем ООП') # запрещаем менять размеры окна, для этого используем свойство resizable tk.resizable(0, 0) # помещаем наше игровое окно выше остальных окон на компьютере, чтобы другие окна не могли его заслонить. Попробуйте �� tk.wm_attributes('-topmost', 1) # создаём новый холст — 400 на 500 пикселей, где и будем рисовать игру canvas = Canvas(tk, width=500, height=400, highlightthickness=0) # говорим холсту, что у каждого видимого элемента будут свои отдельные координаты canvas.pack() # обновляем окно с холстом tk.update() # Описываем класс, который будет отвечать за шарики class Ball: # конструктор — он вызывается в момент создания нового объекта на основе этого класса def __init__(self, canvas, color, x, y, up, down, left, right): # задаём параметры нового объекта при создании # игровое поле self.canvas = canvas # координаты self.x = 0 self.y = 0 # цвет нужен был для того, чтобы мы им закрасили весь шарик # здесь появляется новое свойство id, в котором хранится внутреннее название шарика # а ещё командой create_oval мы создаём круг радиусом 15 пикселей и закрашиваем нужным цветом self.id = canvas.create_oval(10,10, 25, 25, fill=color) # помещаем шарик в точку с переданными координатами self.canvas.move(self.id, x, y) # если нажата стрелка вправо — двигаемся вправо self.canvas.bind_all(right, self.turn_right) # влево self.canvas.bind_all(left, self.turn_left) # наверх self.canvas.bind_all(up, self.turn_up) # вниз self.canvas.bind_all(down, self.turn_down) # шарик запоминает свою высоту и ширину self.canvas_height = self.canvas.winfo_height() self.canvas_width = self.canvas.winfo_width() # движемся вправо # смещаемся на 2 пикселя в указанную сторону def turn_right(self, event): # получаем текущие координаты шарика pos = self.canvas.coords(self.id) # если не вышли за границы холста if not pos[2] >= self.canvas_width: # будем смещаться правее на 2 пикселя по оси х self.x = 2 self.y = 0 # влево def turn_left(self, event): pos = self.canvas.coords(self.id) if not pos[0] = self.canvas_height: self.x = 0 self.y = 2 # метод, который отвечает за отрисовку шарика на новом месте def draw(self): # передвигаем шарик на заданный вектор x и y self.canvas.move(self.id, self.x, self.y) # запоминаем новые координаты шарика pos = self.canvas.coords(self.id) # если коснулись левой стенки if pos[0] = self.canvas_width: self.x = 0 # нижней if pos[3] >= self.canvas_height: self.y = 0 # создаём шарик — объект на основе класса ball_one = Ball(canvas,'red', 150, 150, '', '', '', '') # создаём второй шарик — другой объект на основе этого же класса, но с другими параметрами ball_two = Ball(canvas,'green', 100, 100, '', '', '', '') # запускаем бесконечный цикл while not False: # рисуем шарик ball_one.draw() ball_two.draw() # обновляем наше игровое поле, чтобы всё, что нужно, закончило рисоваться tk.update_idletasks() # обновляем игровое поле и смотрим за тем, чтобы всё, что должно было быть сделано — было сделано tk.update() # замираем на одну сотую секунды, чтобы движение элементов выглядело плавно time.sleep(0.01)

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

Наследование — самый простой механизм в ООП, который в общем виде звучит так:

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

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

В нашей игре мы два раза использовали наследование — когда создавали объекты «Шарик» на основе класса:

# создаём шарик — объект на основе класса ball_one = Ball(canvas,'red', 150, 150, '', '', '', '') # создаём второй шарик — другой объект на основе этого же класса, но с другими параметрами ball_two = Ball(canvas,'green', 100, 100, '', '', '', '')

Два объекта, которые у нас получились, получили все свойства и методы родителя — класса Ball: они умели выводиться на экран в определённом цвете и двигаться.

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

Полиморфизм

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

Классический пример полиморфизма — функция len() в Python, которая возвращает длину указанного в ней объекта:

print(len(‘Привет, это журнал «Код»!’))
# выведет 25

print(len([1,2,3,4,5]))
# выведет 5

Кажется, что это логично, когда функция работает именно так: ты спрашиваешь её длину, она возвращает длину. Но с точки зрения компьютера мы имеем здесь дело с разными типами данных, и совершенно не очевидно, что такое «длина строки» или «длина кортежа». Но благодаря тому, что создатели Python позаботились о полиморфизме, одна и та же функция len() в разных типах данных работает одинаково.

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

# НАСЛЕДОВАНИЕ # новый класс на основе старого class Jumper_ball(Ball): # ПОЛИМОРФИЗМ # этот метод называется так же, как и в старом классе, но мы его подменяем новыми действиями # метод, который отвечает за отрисовку шарика на новом месте def draw(self): # передвигаем шарик на заданный вектор x и y self.canvas.move(self.id, self.x, self.y) # запоминаем новые координаты шарика pos = self.canvas.coords(self.id) # если коснулись левой стенки if pos[0] = self.canvas_width: self.x = -2 # нижней if pos[3] >= self.canvas_height: self.y = -2

Теперь немного поменяем исходный код и сделаем первый шарик на основе старого класса, а второй — на основе нового:

# создаём шарик — объект на основе класса ball_one = Ball(canvas,'red', 150, 150, '', '', '', '') # НАСЛЕДОВАНИЕ # создаём второй шарик — другой объект на основе другого (дочернего) класса, и с другими параметрами ball_two = Jumper_ball(canvas,'green', 100, 100, '', '', '', '')

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

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

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

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

  • геттеры нужны, чтобы узнать значение свойства объекта;
  • а сеттеры — чтобы установить новое значение этому свойству.

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

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

В нашем примере инкапсуляция — это когда мы вызываем метод ball_one.draw() и не лезем внутрь объекта:

  • не берём его свойства;
  • не лезем в его текущее состояние;
  • не проверяем сами его координаты;
  • не пытаемся нарисовать его средствами графической библиотеки.

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

Готовый код

# подключаем графическую библиотеку from tkinter import * # подключаем модули, которые отвечают за время и случайные числа import time # создаём новый объект — окно с игровым полем. В нашем случае переменная окна называется tk, и мы его сделали из класса Tk() — он есть в графической библиотеке tk = Tk() # делаем заголовок окна — Games с помощью свойства объекта title tk.title('Разбираем ООП') # запрещаем менять размеры окна, для этого используем свойство resizable tk.resizable(0, 0) # помещаем наше игровое окно выше остальных окон на компьютере, чтобы другие окна не могли его заслонить. Попробуйте �� tk.wm_attributes('-topmost', 1) # создаём новый холст — 400 на 500 пикселей, где и будем рисовать игру canvas = Canvas(tk, width=500, height=400, highlightthickness=0) # говорим холсту, что у каждого видимого элемента будут свои отдельные координаты canvas.pack() # обновляем окно с холстом tk.update() # Описываем класс, который будет отвечать за шарики class Ball: # конструктор — он вызывается в момент создания нового объекта на основе этого класса def __init__(self, canvas, color, x, y, up, down, left, right): # задаём параметры нового объекта при создании # игровое поле self.canvas = canvas # координаты self.x = 0 self.y = 0 # цвет нужен был для того, чтобы мы им закрасили весь шарик # здесь появляется новое свойство id, в котором хранится внутреннее название шарика # а ещё командой create_oval мы создаём круг радиусом 15 пикселей и закрашиваем нужным цветом self.id = canvas.create_oval(10,10, 25, 25, fill=color) # помещаем шарик в точку с переданными координатами self.canvas.move(self.id, x, y) # если нажата стрелка вправо — двигаемся вправо self.canvas.bind_all(right, self.turn_right) # влево self.canvas.bind_all(left, self.turn_left) # наверх self.canvas.bind_all(up, self.turn_up) # вниз self.canvas.bind_all(down, self.turn_down) # шарик запоминает свою высоту и ширину self.canvas_height = self.canvas.winfo_height() self.canvas_width = self.canvas.winfo_width() # движемся вправо # смещаемся на 2 пикселя в указанную сторону def turn_right(self, event): # получаем текущие координаты шарика pos = self.canvas.coords(self.id) # если не вышли за границы холста if not pos[2] >= self.canvas_width: # будем смещаться правее на 2 пикселя по оси х self.x = 2 self.y = 0 # влево def turn_left(self, event): pos = self.canvas.coords(self.id) if not pos[0] = self.canvas_height: self.x = 0 self.y = 2 # метод, который отвечает за отрисовку шарика на новом месте def draw(self): # передвигаем шарик на заданный вектор x и y self.canvas.move(self.id, self.x, self.y) # запоминаем новые координаты шарика pos = self.canvas.coords(self.id) # если коснулись левой стенки if pos[0] = self.canvas_width: self.x = 0 # нижней if pos[3] >= self.canvas_height: self.y = 0 # НАСЛЕДОВАНИЕ # новый класс на основе старого class Jumper_ball(Ball): # ПОЛИМОРФИЗМ # этот метод называется так же, как и в старом классе, но мы его подменяем новыми действиями # метод, который отвечает за отрисовку шарика на новом месте def draw(self): # передвигаем шарик на заданный вектор x и y self.canvas.move(self.id, self.x, self.y) # запоминаем новые координаты шарика pos = self.canvas.coords(self.id) # если коснулись левой стенки if pos[0] = self.canvas_width: self.x = -2 # нижней if pos[3] >= self.canvas_height: self.y = -2 # создаём шарик — объект на основе класса ball_one = Ball(canvas,'red', 150, 150, '', '', '', '') # НАСЛЕДОВАНИЕ # создаём второй шарик — другой объект на основе другого (дочернего) класса, и с другими параметрами ball_two = Jumper_ball(canvas,'green', 100, 100, '', '', '', '') # запускаем бесконечный цикл while not False: # рисуем шарик ball_one.draw() ball_two.draw() # обновляем наше игровое поле, чтобы всё, что нужно, закончило рисоваться tk.update_idletasks() # обновляем игровое поле и смотрим за тем, чтобы всё, что должно было быть сделано — было сделано tk.update() # замираем на одну сотую секунды, чтобы движение элементов выглядело плавно time.sleep(0.01)

Что дальше

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

Инкапсуляция, полиморфизм, наследование

Все языки OOP, включая С++, основаны на трёх основополагающих концепциях, называемых инкапсуляцией, полиморфизмом и наследованием. Рассмотрим эти концепции.

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

Инкапсуляция (encapsulation) — это механизм, который объединяет данные и код, манипулирующий зтими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В объектно-ориентированном программировании код и данные могут быть объединены вместе; в этом случае говорят, что создаётся так называемый «чёрный ящик». Когда коды и данные объединяются таким способом, создаётся объект (object). Другими словами, объект — это то, что поддерживает инкапсуляцию.

Внутри объекта коды и данные могут быть закрытыми (private). Закрытые коды или данные доступны только для других частей этого объекта. Таким образом, закрытые коды и данные недоступны для тех частей программы, которые существуют вне объекта. Если коды и данные являются открытыми, то, несмотря на то, что они заданы внутри объекта, они доступны и для других частей программы. Характерной является ситуация, когда открытая часть объекта используется для того, чтобы обеспечить контролируемый интерфейс закрытых элементов объекта.

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

2. Полиморфизм

Полиморфизм (polymorphism) (от греческого polymorphos) — это свойство, которое позволяет одно и то же имя использовать для решения двух или более схожих, но технически разных задач. Целью полиморфизма, применительно к объектно-ориентированному программированию, является использование одного имени для задания общих для класса действий. Выполнение каждого конкретного действия будет определяться типом данных. Например для языка Си, в котором полиморфизм поддерживается недостаточно, нахождение абсолютной величины числа требует трёх различных функций: abs(), labs() и fabs(). Эти функции подсчитывают и возвращают абсолютную величину целых, длинных целых и чисел с плавающей точкой соответственно. В С++ каждая из этих функций может быть названа abs(). Тип данных, который используется при вызове функции, определяет, какая конкретная версия функции действительно выполняется. В С++ можно использовать одно имя функции для множества различных действий. Это называется перегрузкой функций (function overloading).

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

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

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

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

Наследование (inheritance) — это процесс, посредством которого один объект может приобретать свойства другого. Точнее, объект может наследовать основные свойства другого объекта и добавлять к ним черты, характерные только для него. Наследование является важным, поскольку оно позволяет поддерживать концепцию иерархии классов (hierarchical classification). Применение иерархии классов делает управляемыми большие потоки информации. Например, подумайте об описании жилого дома. Дом — это часть общего класса, называемого строением. С другой стороны, строение — это часть более общего класса — конструкции, который является частью ещё более общего класса объектов, который можно назвать созданием рук человека. В каждом случае порождённый класс наследует все, связанные с родителем, качества и добавляет к ним свои собственные определяющие характеристики. Без использования иерархии классов, для каждого объекта пришлось бы задать все характеристики, которые бы исчерпывающи его определяли. Однако при использовании наследования можно описать объект путём определения того общего класса (или классов), к которому он относится, с теми специальными чертами, которые делают объект уникальным. Наследование играет очень важную роль в OOP.

Основные принципы ООП: инкапсуляция в программировании

Основные принципы ООП включают в себя инкапсуляцию. Рассмотрим главные преимущества принципа и пример инкапсуляции данных.

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

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

Преимущества принципа инкапсуляции

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

  1. Безопасность данных. Инкапсуляция позволяет защитить данные объекта от некорректного доступа и изменения извне. Класс может предоставлять только определенные методы (геттеры и сеттеры) для доступа к данным, которые проверяют правильность операций и обеспечивают безопасность данных.
  2. Сокрытие реализации. Когда класс инкапсулирует свою реализацию, то изменения внутри класса не отражаются на внешнем коде. Это позволяет менять реализацию объекта, не нарушая функциональность клиентского кода, что облегчает поддержку и эволюцию программы.
  3. Упрощение интерфейса. Инкапсуляция позволяет предоставить простой и понятный интерфейс для работы с объектами. Клиентский код взаимодействует только с публичными методами класса, не требуя знания деталей его внутренней реализации.
  4. Модульность. Инкапсуляция помогает создавать модульные системы, где каждый класс представляет собой отдельный модуль со своими данными и методами. Модули могут взаимодействовать друг с другом через публичные интерфейсы, что способствует повышению читаемости и понимаемости кода.
  5. Принцип единственной ответственности. Инкапсуляция способствует соблюдению принципа единственной ответственности (Single Responsibility Principle). Класс, инкапсулирующий определенные данные и операции с ними, должен отвечать только за эти данные и их обработку.
  6. Контроль доступа. Инкапсуляция ООП позволяет устанавливать уровни доступа к данным и методам класса. Таким образом, некоторые данные и функциональность могут быть скрыты от других классов или пакетов, что способствует защите и контролю кода.

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

Пример инкапсуляции в ООП

Рассмотрим инкапсуляцию на простом примере:

public class BankAccount < private String accountNumber; // Закрытое поле для номера счета private double balance; // Закрытое поле для баланса счета // Конструктор класса public BankAccount(String accountNumber, double initialBalance) < this.accountNumber = accountNumber; this.balance = initialBalance; >// Метод для получения номера счета (getter) public String getAccountNumber() < return accountNumber; >// Метод для получения баланса счета (getter) public double getBalance() < return balance; >// Метод для внесения денег на счет public void deposit(double amount) < if (amount >0) < balance += amount; >> // Метод для снятия денег со счета public void withdraw(double amount) < if (amount >0 && amount > > 

В приведенном примере класс BankAccount инкапсулирует данные о банковском счете ( accountNumber и balance ) и предоставляет интерфейс для работы с ними. Поля accountNumber и balance объявлены как private , что делает их доступными только внутри класса.

10 принципов ООП, о которых стоит знать каждому программисту

Для доступа к данным счета извне класса используются публичные методы (геттеры и сеттеры). В данном случае, методы getAccountNumber() и getBalance() позволяют получить номер счета и баланс соответственно. А методы deposit() и withdraw() предоставляют возможность внести или снять деньги со счета.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *