Как работает инкапсуляция в Java
В ООП инкапсуляция реализуется посредством классов и объектов. Классом называют модель для создания объектов определенного типа. Объекты — это экземпляр класса, который имеет некое состояние, присущее ему поведение, а также выполняет конкретные функции. При инкапсуляции создается отдельная сущность (абстрактный или конкретный класс) с фиксированным набором параметров, которая будет иметь скрытые данные.
Для наглядности разберем принцип работы инкапсуляции данных на примере персонального компьютера.
Представим, что офисный работник включил ПК, запустил браузер и системные программы, после чего приступил к выполнению своих обязанностей. При этом он не знает, какие процессы происходят внутри корпуса. Ему неизвестно, как подключить «маму» и почему может тарахтеть кулер, где находится процессор, чем оперативная память отличается от видеокарты и в какой последовательности это все нужно соединять. То есть ему не нужно быть инженером и понимать внутренние процессы, чтобы включить ПК и начать его использовать.
Процесс, при котором скрываются внутренние процедуры, называют инкапсуляцией. |
В Java инкапсуляции подлежат практически все компоненты, не входящие в интерфейс класса. Для этого переменные объявляются закрытыми, то есть доступ к ним возможен только внутри класса. Внешний доступ обеспечивается посредством публичных методов, предназначенных для извлечения и изменения данных.
Для инкапсуляции данных разработчики используют ряд инструментов.
- Свойства объектов — переменные внутри объектов, предназначенные для хранения данных. При этом их содержимое скрывается по умолчанию. Свойства могут иметь любой тип, а в некоторых случаях даже выступать в роли объектов.
- Методы — функции, отвечающие за выполнение определенного действия. Их можно вызвать только для объекта, которому они принадлежат.
- Геттер — метод для извлечения данных из закрытых переменных. Его название составляется из двух блоков — get и имени объекта. Например, getName.
- Сеттер — метод для изменения значений закрытых переменных. Их имена составляются аналогично геттерам, но в начале ставится слово set.
Геттеры и сеттеры передают данные извне в объект и извлекают их из него. Благодаря этому не нужно разбираться во внутренней структуре и вносить в нее изменения. А значит, снижается риск ошибок во время работы.
- Модификаторы доступа — ключевые слова, которые определяют, могут ли другие сущности влиять на объект, функцию или метод и изменять их. Если модификатор не указан, уровень доступа будет присвоен по умолчанию.
В Java принято использовать три модификатора.
Private — код снаружи не сможет вызвать данные объекта, они будут доступны только для его других составных компонентов.
Public — общедоступный объект, метод, функция. Он доступен для чтения и изменения другими сущностями, поэтому использовать для него setter и getter не нужно. Однако данные с публичным доступом будут уязвимыми.
Protected — управлять содержимым объекта может он сам и его производные.
Пример инкапсуляции в Java
Инкапсуляция позволяет упаковать данные, связав их с управляющим кодом и скрыв от любого другого класса. Рассмотрим на примере кода для вывода имени и возраста пользователя.
Для этого создадим класс «Человек», а затем с помощью модификаторов доступа private и public выполним инкапсуляцию имени (name) и возраста (age). Чтобы объявить новую текстовую переменную, используем тип String; для хранения целых чисел — int. Запуск программы в Java будет выполняться через метод main с параметром String[] args. Это стандартная строка кода, которая пишется как public static void main(String[] args).
Чтобы запустить в Java процесс инкапсуляции, нужно:
- объявить переменные class приватными — в нашем примере это строки private string name и private int age;
- предоставить доступ без ограничений к сеттеру (set) и геттеру (get) с помощью модификатора public.
Так как для переменных мы использовали модификатор private, class Person будет инкапсулированным. При этом методы getter (getAge и getName) в нашем примере кода Java позволят получить доступ к переменным через ключевое слово public. Методы setter (setAge и setName) тоже будут открытыми, поэтому мы сможем менять значения переменных.
Зачем использовать инкапсуляцию
Инкапсуляция упрощает взаимодействие объектов в коде благодаря принципу разделения поведения и логики. Первое отвечает за взаимодействие с другими сущностями, второе — за внутреннее устройство. Это можно сравнить с АКПП автомобиля, когда водителю не нужно помнить о сцеплении и необходимости его выжимать для отключения ведущего вала от трансмиссии.
Инкапсуляция часто используется в программировании, поскольку позволяет разделить масштабный код на отдельные упорядоченные блоки и повысить устойчивость системы к отказу. При разработке ПО эта концепция может быть реализована с разными целями.
- Создание простого и понятного интерфейса для взаимодействия с объектами. При вводе команд будут задействованы только публичные методы класса, то есть пользователю не нужно знать, как реализован сам код.
- Соблюдение принципа единой ответственности. Класс, в котором находятся инкапсулированные данные, отвечает только за них и операции с ними.
- Защита данных. Доступ к объектам обеспечивается с помощью сеттеров и геттеров. Это позволяет исключить внесение некорректных изменений в код и гарантировать, что все операции будут выполняться правильно.
- Создание модульных систем. Модули содержат отдельные наборы методов и данных. При этом они могут взаимодействовать посредством публичных интерфейсов. Благодаря такой структуре код становится более читаемым и простым для понимания.
- Сохранение пользовательского интерфейса. Когда разработчик вносит корректировки в программу, реализация объекта будет изменена, но клиентский код останется прежним.
- Разграничение доступа к методам и данным класса. Например, можно скрыть часть данных от других классов. За счет такого решения повышается уровень безопасности.
Использование инкапсуляции позволяет написать структурированный и защищенный код, который впоследствии может быть расширен. Этот метод хорошо показал себя при работе с большими массивами данных, так как с ним программа становится менее сложной для восприятия.
Например, команда разработчиков работает над масштабным проектом, все блоки которого тесно взаимосвязаны друг с другом. Если внести изменения в один из них, это отразится на работе остальных блоков. В результате стабильность всей системы окажется сниженной. Но при разбивке на отдельные модули с инкапсуляцией проверка кода упрощается за счет повышения его читаемости.
Отличие инкапсуляции от сокрытия
На многих ресурсах сети можно встретить утверждение, что это два разных названия одного и того же понятия. Однако это не совсем так.
Инкапсуляция — используется для обеспечения пользовательского доступа к объекту без понимания подробностей его реализации.
Сокрытие же предназначено для исключения доступа к определенным объектам с целью обеспечения безопасности данных.
Но здесь тоже есть нюансы, которые зависят от языка программирования. Так, в Python сокрытие отсутствует, зато есть инкапсуляция. А в С++ инкапсуляция без сокрытия просто не существует. В Java сокрытием принято считать механизм, с помощью которого реализуется ограниченный доступ к отдельным компонентам объекта.