Что такое инкапсуляция в ООП
Инкапсуляция — это принцип объектно-ориентированного программирования (ООП), который предполагает объединение данных с методами, которые с ними работают, в единое целое. Еще иногда говорят, что данные помещаются в «оболочку», так как инкапсуляция — это также способ скрыть внутреннюю реализацию и ограничить доступ к составляющим объекта так, чтобы избежать их нежелательного чтения, изменения и удаления.
Инкапсуляция в Java
В Java инкапсуляция реализуется путем создания геттеров и сеттеров и применения модификаторов доступа. Ниже они представлены от наименее к наиболее строгим:
- public;
- protected;
- default;
- private.
Ниже представлен простой пример реализации этого принципа в Java:
// Класс Книга
class Book
{
// Инкапсуляция свойств названия книги и ее автора — эти свойства будут доступны только через
// методы
private String title;
private String author;
// Геттер, который возвращает название книги, он будет доступен за пределами объектов класса
public String getTitle()
{
return title;
}
// Сеттер, который устанавливает название книги
public void setTitle(String title)
{
this.title = title;
}
// Геттер, который возвращает имя автора книги
public String getAuthor()
{
return author;
}
// Сеттер, который устанавливает имя автора
public void setAuthor(String author)
{
this.author = author;
}
}
// Класс Библиотека
public class Library
{
public static void main(String[] args)
{
// Создание объекта класса Книга с использованием сеттеров, устанавливающих название и имя автора
Book book = new Book();
book.setTitle("Мастер и Маргарита");
book.setAuthor("Михаил Булгаков");
// Использование геттеров, которые возвращают название книги и имя автора
System.out.println("Название: " + book.getTitle());
System.out.println("Автор: " + book.getAuthor());
}
}
// Вывод: Название: Мастер и Маргарита
Автор: Михаил Булгаков
Этот пример демонстрирует то, как можно управлять доступом к свойствам через методы. Читать и изменять значения свойств title и author напрямую нельзя, это можно сделать, только вызывая методы getTitle, setTitle, getAuthor и setAuthor.
Инкапсуляция в Python
В Python модификаторов доступа не существует. Поэтому инкапсуляция основана на соглашении, которое предписывает именовать атрибуты, начиная с одного (атрибут является защищенным; можно сказать, что это своеобразный аналог protected) или двух (доступ к атрибуту извне запрещен, аналог private) подчеркиваний. Два подчеркивания «включают» name mangling, который усложняет доступ к атрибутам извне, однако и это не является строгой защитой данных. Отсутствие подчеркиваний эквивалентно public.
Рассмотрим небольшой пример:
class Student:
# Конструктор
def __init__(self, name, best_grade):
# Имя будет public
self.name = name
# Лучшая оценка будет private
self.__best_grade = best_grade
# Создание объекта класса Студент
student = Student('Мария', 5)
# Попытка получить доступ к свойству __best_grade
print('Лучшая оценка:', student.__best_grade)
# Вывод: AttributeError: 'Student' object has no attribute '__best_grade'
Инкапсуляция в C++
В C++ инкапсуляция реализуется также с помощью модификаторов доступа и методов для работы со свойствами.
Рассмотрим пример, подобный примеру реализации этого принципа в Java (про классы Книга и Библиотека):
#include <iostream>
#include <string>
using namespace std;
class Book
{
private:
// Инкапсуляция свойств названия и автора книги
string title;
string author;
public:
// Конструктор
Book(string title, string author)
{
this->title = title;
this->author = author;
}
// Сеттер для установки названия книги
void setTitle(string title)
{
this->title = title;
}
// Геттер для получения названия книги
string getTitle()
{
return title;
}
// Сеттер для установки автора книги
void setAuthor(string author)
{
this->author = author;
}
// Геттер для получения автора книги
string getAuthor()
{
return author;
}
};
int main()
{
// Создание объекта класса Книга
Book book("Мастер и Маргарита", "Михаил Булгаков");
// Использование геттеров
cout << "Название: " << book.getTitle() << endl;
cout << "Автор: " << book.getAuthor() << endl;
// Установка значений свойств название и автор
book.setTitle("Руслан и Людмила");
book.setAuthor("Александр Пушкин");
// Вывод новых значений на экран с использованием геттеров
cout << "Название: " << book.getTitle() << endl;
cout << "Автор: " << book.getAuthor() << endl;
return 0;
}
// Вывод: Название: Мастер и Маргарита
Автор: Михаил Булгаков
Название: Руслан и Людмила
Автор: Александр Пушкин
Отличие инкапсуляции от сокрытия
Иногда инкапсуляцию и сокрытие считают синонимами и объединяют в один принцип ООП, но на самом деле эти понятия имеют существенные отличия. Сокрытие данных предполагает обеспечение их безопасности путем частичного или полного ограничения доступа к составляющим объекта. Инкапсуляция же предполагает объединение данных и их методов так, чтобы они образовывали единое целое, что позволяет взаимодействовать с объектом, не вмешиваясь в его внутреннее устройство.
При этом инкапсуляция и сокрытие связаны между собой. Инкапсуляция предусматривает создание интерфейсов для обеспечения контроля доступа к данным, в то время как сокрытие обеспечивает их безопасность. Можно сказать, что инкапсуляция включает в себя сокрытие, при этом само сокрытие не является инкапсуляцией.
Реализация этих принципов отличается от языка к языку. Где-то эти принципы четко разграничены, где-то нет смысла реализовывать инкапсуляцию без сокрытия, а, например, в Python этот принцип реализуется без сокрытия, полагаясь на соглашение между разработчиками.
Преимущества инкапсуляции
Рассмотрим преимущества инкапсуляции:
- этот принцип позволяет управлять доступом к данным и скрывать детали реализации классов;
- повышение гибкости кода: в код легко вносить изменения, которые не повлияют на работу оставшейся части программы, также код легче переиспользовать;
- повышение читаемости кода, упрощение его поддержки, тестирования и отладки.
Как выглядит реализация инкапсуляции
Конкретный вид реализации этого принципа может отличаться в разных языках, но суть остается прежней: этот принцип в ООП основан на создании классов и объектов, которые и представляют из себя «оболочку» для данных (свойств) и функций (методов).
Класс выступает как абстрактное описание, которое определяет общую структуру и поведение будущих объектов этого класса. Объекты же, в свою очередь, объединяют свойства и методы в целостную сущность, тем самым защищая свое содержимое от внешних вмешательств.
Таким образом, реализация инкапсуляции сводится к созданию класса и ограничению уровня доступа к его свойствам, а также определению методов, которые позволят контролировать взаимодействие со свойствами извне.
Как разработчики инкапсулируют данные
Конкретная реализация этого принципа зависит не только от языка программирования, но и от разработчика. Тем не менее есть основные методы и техники, позволяющие инкапсулировать данные:
- Использование модификаторов доступа. Это один из наиболее часто используемых методов инкапсуляции данных, но доступный не в каждом языке программирования. Его суть состоит в ограничении доступа к данным через использование модификаторов доступа: public, private и protected. Public подразумевает, что объект или метод доступен из любого места программы — это удобно, но может нарушать инкапсуляцию и безопасность данных. Private делает содержимое объекта доступным только внутри этого объекта — например, методы не могут вызываться каким-то кодом извне. Protected же подразумевает, что доступ к содержимому объекта разрешен самому объекту и его потомкам. Существуют и другие модификаторы доступа, а также ключевые слова, например, sealed и abstract.
- Реализация геттеров и сеттеров. Это специальные методы, название которых обычно начинается со слов get и set. Эти методы обеспечивают контролируемый доступ к свойствам объекта без вмешательства в его внутреннее устройство — геттеры возвращают текущее значение свойства объекта, а сеттеры изменяют значения свойств.
- Реализация свойств и методов. Свойства (переменные, определенные внутри класса, которые хранят данные) и методы (функции, определенные внутри класса, которые выполняют действия) — это ключевые компоненты классов в ООП, и они тоже играют немаловажную роль при реализации инкапсуляции. Доступ к содержимому свойств может быть ограничен, например, с помощью модификаторов доступа, а методы могут вызываться только для объектов, в которых они определены.
Также нельзя забывать о том, что для грамотной реализации этого принципа специалист должен обладать знаниями и навыками проектирования классов.