Уровень инкапсуляции protected имеют элементы класса которые
Перейти к содержимому

Уровень инкапсуляции protected имеют элементы класса которые

  • автор:

C++. Модификаторы доступа private, protected, public. Инкапсуляция данных в классе

C++. Модификаторы доступа private , protected , public . Инкапсуляция данных в классе

Содержание

  • 1. Случаи применения модификаторов доступа private , protected , public
  • 2. Применение модификаторов доступа для элемента класса
    • 2.1. Модификатор доступа private . Особенности использования
    • 2.2. Модификатор доступа public . Особенности использования
    • 2.3. Модификатор доступа protected . Особенности применения

    Поиск на других ресурсах:

    1. Случаи применения модификаторов доступа private , protected , public

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

    В языке C++ уровень доступности определяется с помощью специальных модификаторов private , protected , public . Применение этих модификаторов может быть использовано в двух случаях:

    • в случае объявления элементов класса. Этот случай рассматривается в данной теме;
    • в случае наследования классов. Более подробно о применении модификаторов доступа при наследовании классов можно посмотреть здесь .
    2. Применение модификаторов доступа для элемента класса
    2.1. Модификатор доступа private . Особенности использования

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

    • элемент недоступен любым экземплярам методов других классов или методов, которые не есть «дружественными» к класу (рисунок 1);
    • элемент недоступен из унаследованных классов (рисунок 2);
    • элемент доступен из методов, которые реализованы в классе (рисунок 3);
    • элемент доступен из дружественных функций (рисунок 4);
    • элемент доступен из методов дружественных классов (рисунок 5).

    C++. Модификатор доступа private. Нет доступа из экземпляра класса к private-элементу класса

    Рисунок 1. Модификатор доступа private . Нет доступа из экземпляра класса к private -элементу value класса

    C++. Модификатор доступа private. Нет доступа к private-элементу класса из унаследованного класса

    Рисунок 2. Модификатор доступа private . Нет доступа к private -элементу класса из унаследованного класса

    C++. Модификатор доступа private. Доступ к элементу класса из внутреннего метода класса

    Рисунок 3. Модификатор доступа private . Доступ к элементу класса из внутреннего метода класса

    C++. Модификатор доступа private. Доступ к элементу класса из дружественной функции (метода)

    Рисунок 4. Модификатор доступа private . Доступ к элементу класса из дружественной функции (метода)

    Если в коде, изображенном на рисунке 4, в объявлении класса A перед именем функции SetValue() убрать ключевое слово friend , то доступа к переменной value класса не будет. Как результат, в функции SetValue() в строке

    компилятор будет выдавать ошибку наподобие

    C++. Модифікатор доступа private. Доступ к private-элементу класса из метода дружественного класса

    Рисунок 5. Модификатор доступа private . Доступ к private -элементу класса из метода дружественного класса

    2.2. Модификатор доступа public . Особенности использования

    Если в классе определен элемент с модификатором доступа public , в этом случае справедливо правило:

    • элемент доступен всем методам в программе.

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

    С++. Модификатор доступа public. Доступ к элементу класса из любого метода в программе

    Рисунок 6. Модификатор доступа public . Доступ к элементу класса из любого метода в программе

    С++. Модификатор доступа public. Доступ из унаследованного класса

    Рисунок 7. Модификатор доступа public . Доступ из унаследованного класса

    2.3. Модификатор доступа protected . Особенности применения

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

    • элемент класса недоступен из любого внешнего метода (рисунок 8) если этот метод не является дружественным;
    • элемент класса доступен из внутренних методов класса (рисунок 8). Здесь следует заметить, что protected -элемент класса также доступен из экземпляра класса, если этот экземпляр объявляется во внутреннем методе класса;
    • элемент класса доступен из дружественных функций класса (рисунок 9);
    • элемент класса доступен из методов дружественного класса (рисунок 9);
    • элемент класса доступен из методов унаследованного класса (рисунок 10);
    • элемент класса недоступен из экземпляров унаследованного класса (рисунок 11). Это правило не касается «дружественных» методов и методов «дружественных» классов.

    C++. Модификатор доступа protected. Нет доступа из экземпляра класса, если этот экземпляр создан в "недружественном" методе

    Рисунок 8. Модификатор доступа protected . Нет доступа из экземпляра класса, если этот экземпляр создан в «недружественном» методе

    На рисунке 8 продемонстрованы два вида доступа к protected -элементу класса:

    • через экземпляр (объект) класса, который объявляется во внутреннем методе класса Method() ;
    • непосредственный доступ как к члену данных класса.

    C++. Модификатор доступа protected. Доступ из "дружественных" методов и методов "дружественных" классов

    Рисунок 9. Модификатор доступа protected . Доступ из «дружественных» методов и методов «дружественных» классов

    C++. Модификатор доступа protected. Доступ из методов унаследованного класса

    Рисунок 10. Модификатор доступа protected . Доступ из методов унаследованного класса

    C++. Модификатор доступа protected. Нет доступа из экземпляров унаследованного класса

    Рисунок 11. Модификатор доступа protected . Нет доступа из экземпляров унаследованного класса

    Инкапсуляция и модификаторы доступа

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

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

    Инкапсуляция – это…

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

    Методы позволяют контролировать обращение к данным, а также предотвратить их удаление или некорректное изменение. Пример – запретить присваивать полю «возраст» объекта «Клиент» число большее 120.

    Основные модификаторы

    Методы доступа к полям изменяются в зависимости от выбранного языка программирования. Основными вариантами для классов объектов программного кода выступают:

    • public;
    • protected;
    • private;
    • internal.

    У каждого ЯП свои «дополнительные» модификаторы. Так называют специфичную часть языков программирования для облегчения инкапсуляции. Ключевые слова в ООП, которые задают параметры доступа для классов, методов и иных объектов кода.

    Private

    Это закрытый или «приватный» элемент класса или структуры. Он будет доступен только в пределах собственного класса. Для того чтобы объявить такой модификатор, нужно использовать ключевое слово private.

    При его применении относящиеся к «приватному» типу доступа поля нельзя изменять нигде, кроме как в methods того или иного класса. Значение извне получить тоже не представляется возможным. При попытках это сделать система выведет на экран ошибку. Для устранения неполадки можно использовать:

    • ключевое слово readonly, но оно запрещает корректировать значение;
    • передачу значения «приватного» члена класса через публичный.

    В C# применяется третья концепция – это свойства.

    Также есть private protected. Компонент класса будет доступен из любого места в своем классе или в производных классах, определенных в той же сборке. Private protected используется в C#. В случае с Java применяется только ключевое слово «протектед».

    Internal

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

    Здесь класс Backpack используется только в пределах файла Program.cs. Если попытаться объявить его внутри другого файла, возникнет ошибка.

    Public

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

    Public – это самый простой модификатор. С ним сталкиваются все программисты. Называется «публичным» или «общедоступным». Разница с «протектед» очевидна – компонент будет доступен по всему коду. А еще – из других программ и сборок.

    Для работы с таким вариантом используется ключевое слово public. Вот – пример приложения с class Item:

    Если объявить экземпляр class, можно обратиться к любым его полям в любом месте приложения. Главное, чтобы сам объект был доступен.

    Static

    Изучая модификаторы private, public и другие в заданном языке программирования, нужно обратить внимание на ключевое слово static.

    Статичность – понятие, которое не совсем относится к уровням доступа. Оно помогает заключать реализацию функционала в оболочку класса. Статичность позволяет обращаться к методом или полям без создания объекта.

    1. Можно не использовать public and protected.
    2. Метод Sum() применяется в Program, несмотря на то, что экземпляр Calc не создавался.
    3. Статичным можно сделать отдельный параметр или метод, а также весь class. Для этого все соответствующие элементы должны стать static.

    Вместо private and protected используется static, когда требуется создать набор инструментов для его дальнейшего применения в других частях приложения.

    Сравнительные таблицы

    Каждая программа будет работать в зависимости от способа настройки модификаторов доступа. Эта таблица поможет лучше понять, чем отличается private от public и других спецификаторов:

    Название модификатора Границы видимости Краткая характеристика
    Public Доступ всем и с любого места Доступ к полям будут иметь все
    Private Доступ «мне и только мне» Элементы доступны только class, в котором они объявлены
    Package «Мне, а также всем в пределах пакета» Доступ будет иметь не только class, в котором объявлены поля и методы, но и все классы, относящиеся к тому же пакету
    Protected «Мне и всем наследникам» Доступом обладает класс, в котором объявлены поля, а также все classes в пакете и потомки

    Public and protected легко спутать, особенно новичкам.

    Выше – таблица, которая поможет лучше разобраться с особенностями спецификаций C#. Они могут применяться как к компонентам class, так и к компонентам структуры. Во втором случае нельзя использовать private and protected, а также protected и protected internal. Связано это с тем, что структуры не поддерживают наследование. Здесь расположен видео-урок по изученной теме на примере Java.

    Как освоить тему

    Любой язык программирования предусматривает свои особенности и спецификации доступа. Чтобы лучше изучить private, public, static, new string и другие записи выбранного ЯП, рекомендуется закончить специализированные дистанционные компьютерные курсы. Пример – от OTUS. В данном образовательном центре можно быстро освоить инновационные IT-профессии, а также современные языки разработки с нуля.

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

    2.4. Инкапсуляция в c#

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

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

    Модификаторы доступа С#

    Модификатор доступа (к чему применяется)

    public (типы или члены типов)

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

    private (члены типов или вложенные типы)

    Приватные (private) элементы могут быть доступны только в классе (или структуре), в котором они определены

    protected (члены типов или вложенные типы)

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

    internal (типы или члены типов)

    Внутренние (internal) элементы доступны только в пределах текущей сборки. Таким образом, если в библиотеке классов .NET определен набор внутренних типов, то другие сборки не смогут ими пользоваться

    protected internal (члены типов или вложенные типы)

    Когда ключевые слова protected и internal комбинируются в объявлении элемента, такой элемент доступен внутри определяющей его сборки, определяющего класса и всех его наследников

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

    // Класс с единственным общедоступным полем.

    public int numberOfPages;

    Проблема с общедоступными данными состоит в том, что сами по себе эти данные не имеют возможности распознать, является ли присваиваемое значение допустимым в рамках существующих бизнес-правил системы. Как известно, верхний предел значений для типа int в С# довольно велик B 147 483 647), поэтому компилятор разрешит следующее присваивание:

    //Хм… Ничего себе — мини-новелла!

    static void Main(string[] args)

    Book miniNovel = new Book();

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

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

    • определение пары методов доступа и изменения;

    • определение свойства .NET.

    Свойство — способ доступа к внутреннему состоянию объекта, имитирующий переменную некоторого типа. Обращение к свойству объекта реализовано через вызов функции. При попытке задать значение данного свойства вызывается один метод, а при попытке получить значение данного свойства — другой. Свойства в C# — поля с логическим блоком, в котором есть ключевые слова get и set.

    Name already in use

    JBook / oop / encapsulation.md

    • Go to file T
    • Go to line L
    • Copy path
    • Copy permalink
    • Open with Desktop
    • View raw
    • Copy raw contents Copy raw contents

    Copy raw contents

    Copy raw contents

    Слово Инкапсуляция происходит от лат. in capsula , capsula — «коробочка».

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

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

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

    Представьте себе автомобиль. По сути, все, что является внутренностями машины, скрыто от вас, а открытое API — это руль и педали. Т.е все, что вам доступно — это только то, что вам необходимо для взаимодействия с объектом, в нашем случае — с автомобилем.

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

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

    Как вы думаете: как долго ваша система проживет?

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

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

    Java , как ООП язык, предоставляет нам несколько инструментов для обеспечения инкапсуляции : модификаторы доступа и пакеты.

    В начале давайте поговорим про то, что такое пакет .

    Представим, что в нашем проекте несколько сотен, а то и тысяч классов.

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

    Я думаю, вы уже начали догадываться к чему я клоню: представьте тысячу файлов в одной директории! А если классов более тысячи? Или же вы подключили стороннюю библиотеку, в которой есть классы, с такими же именами, что и у вас в проекте?

    В таком хаосе нельзя остаться верным императору и не запутаться во тьме.

    Логично, что надо попытаться структурировать их: разнести по нескольким директориям, тем самым создать дерево директорий, в котором легко ориентироваться. Именно это и сделано в Java . Только вместо директории мы говорим пакет .

    Для описания того, что класс относится к пакету используется ключевое слово package .

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

    Это описание, если оно есть, должно быть первым, только комментарии могут быть раньше него.

    Таким образом класс HashUtils принадлежит пакету hash , который является вложенным в пакет utils , который в свою очередь также вложен в aarexer .

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

    Этому джентльменскому соглашению придерживается большинство компаний и разработчиков, например, класс FileUtils у apache-commons лежит в пакете:

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

    В качестве примера можно привести: java.awt.List и java.util.List . Это два разных класса с одним названием, однако, благодаря тому, что они логически разделены пакетами, а пакет является частью полного имени класса, все становится на свои места.

    Разделение на пакеты

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

    Примерами могут служить пакет java.swing , где собраны классы отвечающие за работу с библиотекой swing или же пакет javafx.scene.control , где можно найти все для работы с контролами — кнопки, комбо-боксы и т.д

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

    Например, вы пишите библиотеку, где внутренние компоненты взаимодействуют посредством класса Event — событий. Т.е ваши внутренние компоненты пересылают друг другу события, вы вводите сущность некоторого служебного события. Этот класс — внутренний для нашей библиотеки, мы не хотим и не собираемся его ‘светить’ наружу, так как он нужен нам только для внутреннего использования.

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

    Доступ мне и всем в пределах пакета, всем соседям.

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

    Теперь поговорим про модификаторы доступа.

    Модификатор доступа — это ключевое слово Java для задания области видимости полей, методов и классов.

    В Java существует целых 4 модификатора доступа:

    Доступ всем и отовсюду .

    К полям, методам и классам, объявленным как public доступ имеет кто угодно.

    Доступ мне и только мне .

    К полям, методам и классам, объявленным как private , имеет доступ только класс , в котором они объявлены.

    Доступ мне и всем в пределах пакета, всем соседям

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

    Доступ мне и всем наследникам

    К полям, методам и классам, объявленным как protected , имеет доступ класс , в котором они объявлены, все классы , находящиеся в том же самом пакете и все классы -потомки, все классы, унаследованные от того, где сделано объявление.

    Крайне важно помнить, что в Java модификатор доступа protected дает также доступ и всем в пакете! Это очень странное решение от создателей, однако так сделано и это просто надо помнить.

    Сведем все в одну таблицу для наглядности:

    Модификатор доступа Границы видимости Описание
    public Доступ всем и отовсюду . К полям, методам и классам, объявленным как public доступ имеет кто угодно.
    private Доступ мне и только мне . К полям, методам и классам, объявленным как private , имеет доступ только класс , в котором они объявлены.
    package Доступ мне и всем в пределах пакета, всем соседям К полям, методам и классам, объявленным package , имеет доступ не только класс , в котором они объявлены, но и все классы , находящиеся в том же самом пакете .
    protected Доступ мне и всем наследникам К полям, методам и классам, объявленным как protected , имеет доступ класс , в котором они объявлены, все классы , находящиеся в том же самом пакете и все классы -потомки.

    Модификаторы доступа и наследование

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

    Например, если метод public , то в классе наследнике не получится уровень доступа изменить на private .

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

    Это отсылает нас к SOLID, а если быть точнее, то к L — The Liskov Substitution Principle.

    Класс наследник должен дополнять, а не изменять базовый.

    Советы по использованию

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

    Если ваш класс используется только в области видимости пакета — сделайте такой класс доступным только в пакете с помощью package . Тогда такой класс перестанет быть доступным извне, он станет частью реализации пакета.

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

    Модификатор доступа protected используется в основном тогда, когда вы планируете использовать это поле/метод в наследовании. После public это наиболее открытый модификатор. Соответсвенно, исходя из описания, не следует применять его вне того, для чего он обычно используется.

    Наиболее часто злоупотребляют использованием модификатора public , поэтому разберем его подробнее.

    Когда вы объявляете поле или метод как public вы по сути включаете его в API класса.

    В случае, если это действительно часть API , без которого взаимодействие с классом и его объектами невозможно — это оправдано.

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

    Почему? Давайте разбираться!

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

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

    Грубо говоря, каждой кнопке и рычагу соответствует какой-то метод. Если вы добавляете функцию автоматических дворников — логично, что этому должна соответствовать какая-то кнопка, т.е это public -метод. А вот если вы делаете функцию подачи горючего в двигатель, то выносить это на приборную панель — губительная практика.

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

    Поэтому отдавайте себе отчет: что выносить в интерфейс класса, а что нет.

    Чего надо опасаться, когда объявляем public поле и о чем надо задумываться?

    В первую очередь, это то, что большинство объектов в Java — изменяемые. И ссылки на объекты по умолчанию тоже изменяемые.

    Это значит, что задав public на такое поле кто-то просто может изменить не только состояние вашего объекта, но и поведение!

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

    Теперь создадим несколько экзмепляров класса и в одном из них изменим возраст:

    И что же мы видим? А видим мы Александра в возрасте минус сто.

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

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

    Однако тут же встает и еще один вопрос: закрыть-то мы закроем, а как обращаться теперь к полю? И как менять возраст?

    Для этих целей существуют так называемые getter -ы и setter -ы.

    Давайте модернизируем наш класс:

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

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

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

    Т.е инкапсуляция — это еще и контроль за валидностью данных.

    Не надо быть провидцем, чтобы почувствовать вопрос, который уже давно витает в воздухе.

    Вопрос:

    Когда же безопасно использовать public ?

    Ответ:

    С final -полями и неизменяемыми объектами.

    Например, при объявлении констант.

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

    Для объявления константы, входящей в API класса можно использовать конструкцию вида: public static final . Часто константы группируют логически и выносят в отдельные классы, например, как показано вот тут.

    Также, если ваш объект не изменяемый( immutable ) и должен входить в интерфейс класса, то вполне допустимо использовать public final . Ведь объект — неизменяемый, а значит и навредить ему или изменить его нельзя, а благодаря ключевому слову final вы закрываете возможность подменить этот объект на другой.

    Однако, даже использование final не спасет, если объект может менять свое состояние, т.е является изменяемым, mutable -объектом. Как например, массивы или коллекции.

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

    Вопросы для закрепления

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

    Вопрос 0:

    Есть ли ограничения на то, кому какой модификатор доступа поставить? Какие модификаторы доступа можно ставить полям класса? Методам? Самим классам?

    Ответ:

    У членов класса(полей, методов и конструкторов) ограничений нет, могут быть любые. Сами классы могут быть public и package . Внутренние классы могут быть объявлены с любым модификатором доступа, так как в этом плане не отличаются от членов класса.

    Вопрос 1:

    Какой модификатор доступа будет у конструктора по умолчанию?

    Ответ:

    Тут все просто — модификатор доступа для конструктора по умолчанию будет такой же, какой модификатор доступа у класса.

    Вопрос 2:

    Зачем нужен private конструктор? А protected конструктор?

    Ответ:

    Напомним, что конструктор — это способ инициализации экземпляра создаваемого объекта. У класса может быть несколько конструкторов, это просто несколько способов создания. Логично, что и на эти способы хотелось бы иметь возможность навешивать какие-то ограничения.

    С private конструктором все довольно прозрачно. Это средство создания объектов класса, зарезервированное для нас самих и только для нас. Соответственно, в классе-наследнике вы его не вызовете.

    С protected конструктором дело обстоит чуть интереснее.

    Он может использоваться в двух случаях.

    protected конструктор может вызываться в качестве конструктора родительского класса. Т.е через вызов super(. ) .

    protected конструктор может вызываться в простой конструкции new , но только внутри пакета, где определен класс.

    Вопрос 3:

    Разрешен ли доступ к private методам и полям в одном экземпляре класса к другому экземпляру того же класса?

    Будет ли валиден такой код?

    Ответ:

    Такой код валиден и разрешен.

    Ограничение private не ограничивает доступ экземплярам класса друг к другу. Более того, это распространяется и на статические методы – т.е. если в статический метод класса A передать экземпляр класса A , то внутри этого метода разрешен доступ ко всем private -членам переданного экземпляра.

    Вопрос 4:

    А что будет, если у нас есть еще и класс наследник и он в другом пакете?

    Будет ли валиден такой код?

    Обратите внимание на пакеты и модификаторы доступа!

    Ответ:

    Нет! Такой код будет не валиден.

    При этом, если мы изменим тип аргумента other с TestParent на TestChild код уже будет валидным.

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

    Как говорила моя учительница по английскому: «To sum up»!

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

    Т.е данные и методы связаны в едином объекте. Концепция подразумевает использование объекта путем предоставления интерфейса взаимодействия и сокрытия деталей его реализации.

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

    В Java существует четыре модификатора доступа: public , protected , package и private . Основное правило их применения в том, что чем строже уровень доступа — тем лучше.

    Так как public дает доступ до поля/метода всем, то старайтесь не использовать его для изменяемых объектов, либо контролируйте изменения. Помните, что public добавляет поле/метод в API класса!

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

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