Главная » Java » Применение методов для управления доступом

0

Вариант класса Body, предусматривающий использование различных конструкторов, значительно легче применять, нежели простую версию класса, в которой содержатся только поля данных, поскольку, в частности, мы всегда уверены в том, что поле idNum получит верное значение без дополнительных воздействий извне. Но программисту, который собирается воспользоваться нашим классом, трудно уберечься от искушения обратиться к полям построенного объекта напрямую, поскольку то же поле idNum объявлено нами как publiс, Т.е. полностью открыто для доступа извне. Исходя из семантики класса Body содержимое переменной idNum позволяется только "читать". Данные объекта, доступные исключительно для чтения, – это достаточно типичная структура хранения информации, но в языке нет специального служебного слова, которым можно было бы пометить поле, предоставляющее ограниченный доступ "снаружи" и полный – "изнутри" (ведь должен же сам класс как-то управлять собственными данными!).

Для реализации модели данных, открытых только для чтения, существуют две возможности: вы должны либо обозначить поле как final (и тогда оно приобретет свойство "только для чтения" на весь период жизни объекта), либо каким-то образом скрыть его от постороннего воздействия. Сначала поговорим о втором варианте. Чтобы "скрыть" поле (например, idNum), достаточно снабдить его объявление модификатором ргivate и создать новый метод, который должен выполнять функцию посредника между полем и внешним кодом:

 

class Body {

        private long idNum; // теперь уже private

        public String name = "<Без имени>";

        public Body orbits = null;

        private static long nextID = 0;

        Body() {

        idNum = nextID++;

        }

        public long getID() {

                       return idNum;

        }

}

 

Теперь программист, заинтересованный в получении порядкового номера небесного тела, должен обратиться к методу getID, который возвращает требуемое значение. Для прикладной программы больше не существует способов изменения содержимого поля – оно фактически приобретает искомое свойство "только для чтения". Но возможности доступа к полю private со стороны методов класса Body остаются по-прежнему полными.

Методы, управляющие доступом к внутренним полям данных класса, иногда

так и называют – методами доступа (accessor methods).

Даже в том случае, если на данной стадии программного проекта, как кажется, нет насущной необходимости в ограничении доступа к полям класса, вы как автор поступите предусмотрительно и дальновидно, обозначив поля модификатором private и включив в состав класса специальные методы для присваивания и считывания данных. Если пользователи обладают возможностью обращения к полю класса напрямую, вы не сможете проконтролировать, какие значения ими задаются, и предусмотреть все мыслимые последствия изменения этих значений. Кроме того, поле, открытое для доступа, становится частью контракта класса – позже вы не сможете изменить реализацию класса, не заставив десятки (а возможно, и тысячи) счастливых обладателей вашего продукта перекомпилировать собственные приложения. Рассмотрим следующую ситуацию: будущая версия класса Body, возможно, потребует реализации средств поиска порядкового номера небесного тела в таблице базы данных, индексированной по столбцу наименования, причем найденный номер вовсе не обязательно должен будет сохраняться в объекте класса. Подобное изменение не может быть внесено, если поле idNum свободно для доступа. Итак, предупреждаем заранее: в последующих примерах, приведенных на страницах нашей книги, вы увидите очень мало объявлений полей, обозначенных модификатором publiс или protected, – мы сами строго и последовательно придерживаемся концепции сокрытия данных посредством методов и рекомендуем вам поступать так же.

О методах, позволяющих задавать (set) значения полей объекта и считывать (get) их, иногда говорят, будто они определяют свойства (properties) объекта. (В русскоязычной литературе термин свойства иногда употребляется для обозначения всех элементов данных (полей) класса. – Прим. перев.) Так, например, относительно метода getID класса Body можно было бы сказать, что он относится к свойству ID объекта (свойство ID реализовано посредством поля idNum). В некоторых программных системах (включая, например, те, которые относятся к компонентной архитектуре JavaBeans™) подобные соглашения используются для реализации средств автоматического управления свойствами объектов (за дополнительными справками обращайтесь к разделу 20.3 на странице 551). Теперь, возвращаясь к примеру класса Body, мы можем и должны снабдить поля main и orbits модификаторами private и предоставить соответствующие методы set и get:

class Body {

private long idNum;

private String name = "<Без имени>";

private Body orbits = null;

private static long nextID = 0ж

// объявления конструкторов опущены

public long getID() {

return idNum;

 }

 public String getName() {

return name;

}

public void setName(String newName) {

name = neWName;

}

public Body getorbits() {

return orbits;

}

public void setorbits(Body orbitsAround) {

orbits = orbitsAround;

}

}

Модификатор final подчас применяется в качестве альтернативного средства управления доступом, предотвращающего возможность изменения содержимого полей объекта. Но не стоит путать грешное с праведным – обеспечение устойчивости данных к изменениям с регулированием уровней доступа к данным. Если поле не допускает изменения значений, его следует объявить как final, независимо от того, кто и как может к нему обращаться. И наоборот, если поле не должно стать частью контракта класса, поле надлежит скрыть, не принимая во внимание, позволено модифицировать его содержимое или нет.

Теперь, когда все поля класса Body снабжены модификаторами private, уместно вернуться к высказанному ранее тезису о том, что признак доступности данных – это атрибут класса, а не частного объекта. Предположим, что одно небесное тело способно "захватить" другое и заставить последнее изменить свою орбиту. Соответствующий метод класса Body мог бы выглядеть так:

public void capture(Body victim) {   // Захват жертвы

victim.orbits = this;

}

Если бы доступ к полям данных регулировался на уровне объекта, метод capture (захват), будучи вызванным в одном объекте, не смог бы обратиться к при ватному полю другого объекта класса (жертва). Но поскольку возможности доступа устанавливаются на уровне класса, код метода класса способен обращаться ко всем полям всех объектов этого класса – ему достаточно иметь в своем распоряжении ссылку на нужный объект (такую как victim в нашем примере). Некоторые объектно-ориентированные ЯЗЬ,IКИ программирования пропагандируют средства управления доступом к данным на уровне объектов, но Java не относится к их числу.

Упражнение 2.12. Объявите поля класса Vehicle как private и предложите методы доступа для них. Для каких полей следует предусмотреть соответствующий метод задания (set) значения, а для каких нет?

Упражнение 2.13. Объявите поля класса LinkedList как private и предложите методы доступа для них. Для каких полей следует предусмотреть соответствующий метод задания значения, а для каких нет?

Упражнение 2.14. Добавьте в состав класса Vehicle метод changeSpeed, Предусматривающий изменение текущей скорости движения автомобиля в соответствии с переданным значением-аргументом, и метод stop, который "снижает" скорость до нуля.

Упражнение 2.15. Пополните класс LinkedList объявлением метода, способного возвратить текущее количество элементов в связанном списке.

Источник: Арнолд, Кен, Гослинг, Джеймс, Холмс, Дэвид. Язык программирования Java. 3-е изд .. : Пер. с англ. – М. : Издательский дом «Вильяме», 2001. – 624 с. : ил. – Парал. тит. англ.

По теме:

  • Комментарии