русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Protected


Дата добавления: 2015-06-12; просмотров: 654; Нарушение авторских прав


Чтобы понять смысл спецификатора доступа protected, необходимо немного забежать вперед. Сразу скажу, что понимание этого раздела не обязательно до знакомства с наследованием (глава 7). И все же для получения цельного представления здесь приводится описание protected и примеры его использования.

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

class Foo extends Bar {}

Остальная часть реализации выглядит как обычно.

Если при создании нового пакета используется наследование от класса, находящегося в другом пакете, новый класс получает доступ только к открытым (public) членам из исходного пакета. (Конечно, при наследовании в пределах одного пакета можно получить доступ ко всем членам с пакетным уровнем доступа.) Иногда создателю базового класса необходимо предоставить доступ к конкретному методу производным классам, но закрыть его от всех остальных. Именно для этой задачи используется ключевое слово protected. Спецификаторprotected также предоставляет доступ в пределах пакета — то есть члены с этим спецификатором доступны для других классов из того же пакета.

Интерфейс и реализация

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

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



Это подводит нас непосредственно ко второй причине — разделению интерфейса и реализации. Если в программе использована определенная структура, но программисты-клиенты не могут получить доступ к ее членам, кроме отправки сообщений рubliс-интерфейсу, вы можете изменять все, что не объявлено как public (члены с доступом в пределах пакета, protected и private), не нарушая работоспособности изменений клиентского кода.

Для большей ясности при написании классов можно использовать такой стиль: сначала записываются открытые члены (public), затем следуют защищенные члены (protected), потом — с доступом в пределах пакета и наконец закрытые члены (private). Преимущество такой схемы состоит в том, что при чтении исходного текста пользователь сначала видит то, что ему важно (открытые члены, доступ к которым можно получить отовсюду), а затем останавливается при переходе к закрытым членам, являющимся частью внутренней реализации:

//: access/OrganizedByAccess.java

 

public class OrganizedByAccess {

public void pub1() { /* ... */ }

public void pub2() { /* ... */ }

public void pub3() { /* ... */ }

private void priv1() { /* ... */ }

private void priv2() { /* ... */ }

private void priv3() { /* ... */ }

private int i;

// ...

}

Такой подход лишь частично упрощает чтение кода, поскольку интерфейс и реализация все еще совмещены. Иначе говоря, вы все еще видите исходный код — реализацию — так, как он записан прямо в классе. Вдобавок документация в комментариях, создаваемая с помощью javadoc, снижает необходимость в чтении исходного текста программистом-клиентом.

 

Доступ к классам

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

Для управления доступом к классу, спецификатор доступа записывается перед ключевым словом class:

public class Widget {}

Если ваша библиотека называется, например, access, то любой программист-клиент сумеет обратиться извне к классу Widget:

import access.Widget;

или

import access *;

Впрочем, при этом действуют некоторые ограничения:

· В каждом компилируемом модуле может существовать только один открытый (public) класс. Идея в том, что каждый компилируемый модуль содержит определенный открытый интерфейс и реализуется этим открытым классом. В модуле может содержаться произвольное количество вспомогательных классов с доступом в пределах пакета. Если в компилируемом модуле определяется более одного открытого класса, компилятор выдаст сообщение об ошибке.

· Имя открытого класса должно в точности совпадать с именем файла, в котором содержится компилируемый модуль, включая регистр символов. Поэтому для класса Widget имя файла должно быть Widget.java, но никак не widget.java или WIDGET.java. В противном случае вы снова получите сообщение об ошибке.

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

Допустим, в пакете access имеется класс, который всего лишь выполняет некоторые служебные операции для класса Widget или для любого другого рublic-класса пакета. Конечно, вам не хочется возиться с созданием лишней документации для клиента; возможно, когда-нибудь вы просто измените структуру пакета, уберете этот вспомогательный класс и добавите новую реализацию. Но для этого нужно точно знать, что ни один программист-клиент не зависит от конкретной реализации библиотеки. Для этого вы просто опускаете ключевое слово public в определении класса; ведь в таком случае он ограничивается пакетным доступом, то есть может использоваться только в пределах своего пакета.

При создании класса с доступом в пределах пакета его поля все равно рекомендуется помечать как private (всегда нужно по максимуму перекрывать доступ к полям класса), но методам стоит давать тот же уровень доступа, что имеет и сам класс (в пределах пакета). Класс с пакетным доступом обычно используется только в своем пакете, и делать методы такого класса открытыми (public) стоит только при крайней необходимости — а о таких случаях вам сообщит компилятор.

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

// Demonstrates class access specifiers. Make a class

// Спецификаторы доступа для классов.

// Использование конструкторов, объявленных private,

// делает класс недоступным при создании объектов.

 

class Soup1 {

private Soup1() {}

// (1) Разрешаем создание объектов в статическом методе::

public static Soup1 makeSoup() {

return new Soup1();

}

}

 

class Soup2 {

private Soup2() {}

// (2) Создаем один статический объект и

// по требованию возвращаем ссылку на него):

private static Soup2 ps1 = new Soup2();

public static Soup2 access() {

return ps1;

}

public void f() {}

}

 

// В файле может быть определен только один public-класс:

public class Lunch {

void testPrivate() {

// Запрещено, т.к конструктор объявлен приватным::

//! Soup1 soup = new Soup1();

}

void testStatic() {

Soup1 soup = Soup1.makeSoup();

}

void testSingleton() {

Soup2.access().f();

}

}

До этого момента большинство методов возвращало или void, или один из примитивных типов, поэтому определение:

public static Soupl makeSoup(){ return new Soup1()}

на первый взгляд смотрится немного странно. Слово Soup1 перед именем метода (makeSoup) показывает, что возвращается методом. В предшествующих примерах обычно использовалось обозначение void, которое подразумевает, что метод не имеет возвращаемого значения. Однако метод также может возвращать ссылку на объект; в данном случае возвращается ссылка на объект класса Soup1.

Классы Soup1 и Soup2 наглядно показывают, как предотвратить прямое создание объектов класса, объявив все его конструкторы со спецификатором private. Помните, что без явного определения хотя бы одного конструктора компилятор сгенерирует конструктор по умолчанию (конструктор без аргументов). Определяя конструктор по умолчанию в программе, вы запрещаете его автоматическое создание. Если конструктор объявлен со спецификатором private, никто не сможет создавать объекты данного класса.

Но как же тогда использовать этот класс? Рассмотренный пример демонстрирует два способа. В классе Soup1 определяется статический метод, который создает новый объект Soup1 и возвращает ссылку на него. Это бывает полезно в ситуациях, где вам необходимо провести некоторые операции над объектом перед возвратом ссылки на него, или при подсчете общего количества созданных объектов Soup1 (например, для ограничения их максимального количества).

В классе Soup2 использован другой подход — в программе всегда создается не более одного объекта этого класса. Объект Soup2 создается как статическая приватная переменная, пoтому он всегда существует только в одном экземпляре и его невозможно получить без вызова открытого метода access().

Резюме

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

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

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

По оценкам проекты на языке C начинают «рассыпаться» примерно тогда, когда код достигает объема от 50 до 100 Кбайт, так как C имеет единое «пространство имен»; в системе возникают конфликты имен, создающие массу неудобств. В Java ключевое слово package, схема именования пакетов и ключевое слово import обеспечивают полный контроль над именами, так что конфликта имен можно легко избежать.

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

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

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


 



<== предыдущая лекция | следующая лекция ==>
Private | Глава 7 ПОВТОРНОЕ ИСПОЛЬЗОВАНИЕ КЛАССОВ


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.1 сек.