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

18.5. Инкапсуляция

В разделе 13.1 мы обсуждали тот факт, что в языке С нет специальной конст­рукции инкапсуляции, а в разделе 13.5 отметили, что операция разрешения области действия и конструкция namespace (пространство имен) в C++ уточ­няет грубое приближение языка С к проблеме видимости глобальных имен. Для совместимости в язык C++ также не была включена конструкция инкап­суляции; вместо этого сохраняется зависимость от «h»-файлов. В Ada есть конструкция пакета, которая поддерживает инкапсуляцию конструкций в мо­дули (см. раздел 13.3), причем спецификации пакетов и их реализации (тела) могут компилироваться отдельно. Конструкции with позволяют разработчику программного обеспечения точно определить зависимости между модулями и использовать порожденные пакеты (кратко упомянутые в разделе 15.2) для разработки модульных структур с иерархической достижимостью.

Java содержит конструкцию инкапсуляции, названную пакетом (package), но, к сожалению, конструкция эта по духу ближе к пространству имен (names­pace) в языке C++, чем к пакету Ada! Пакет является совокупностью классов:

package Airplane_Package;

public class Airplane_Data

Java

{

int speed; // Доступно в пакете

private int mach_speed; // Доступно в классе

public void set_speed(int s) {...}; // Глобально доступно

public int get_speed() {...};

}

public class Airplane_Database

{

public void new_airplane(Airplane_Data a, int i)

{

if (a.speed > 1000) // Верно !

a.speed = a.mach_speed; // Ошибка !

}

private Airplane_Data[ ] database = new Airplane_Data[1000];

}

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

Спецификаторы public и private аналогичны принятым в языке C++: pub­lic (общий) означает, что элемент доступен за пределами класса, в то время как private (приватный) ограничивает достижимость для других членов класса. Ес­ли никакой спецификатор не задан, то элемент видим внутри пакета. В приме­ре мы видим, что элемент int speed (скорость) класса Airplane_Data не имеет никакого спецификатора, поэтому к нему может обратиться оператор внутри класса Airplane_Database, так как два класса находятся в одном и том же паке­те. Элемент mach_speed объявлен как private, поэтому он доступен только внутри класса Airplane_Data, в котором он объявлен.

Точно так же классы имеют спецификаторы достижимости. В примере оба класса объявлены как public, что означает, что другие пакеты могут обращать­ся к любому (public) элементу этих классов. Если класс объявлен как private, он доступен только внутри пакета. Например, мы могли бы объявить private класс Airplane_File, который использовался бы внутри пакета для записи в ба­зу данных.

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

Сравнение с другими языками

Пакеты Java служат для управления глобальными именами и достижимостью аналогично конструкции namespace в языке C++. При заданных в нашем примере объявлениях любая Java-программа может содержать:

Java

Airplane_Package.Airplane_Data a;

a.set_speed(100);

потому что имена класса и метода объявлены как public. He изучив полный исходный текст пакета, нельзя узнать, какие именно классы импортированы. Есть оператор import, который открывает пространство имен пакета, разре­шая прямую видимость. Эта конструкция аналогична конструкциям using в C++ и uses Ada.

Основное различие между Java и Ada состоит в том, что в Ada специфика­ция пакета и тело пакета разделены. Это не только удобно для сокращения размера компиляций, но и является существенным фактором в разработке и поддержке больших программных систем. Спецификация пакета может быть заморожена, позволяя параллельно разрабатывать тело пакета и вести разработку других частей. В Java «интерфейс» пакета является просто совокупно­стью всех public-объявлений. Разработка больших систем на Java требует, что­бы программные инструментальные средства извлекали спецификации паке­та и гарантировали совместимость спецификации и реализации.

Конструкция пакета дает Java одно главное преимущество перед C++. Пакеты сами используют соглашение об иерархических именах, которое позволяет компилятору и интерпретатору автоматически размещать клас­сы. Например, стандартная библиотека содержит функцию, названную Java.lang.String.toUpperCase. Это интерпретируется точно так же, как опе­рационная система интерпретирует расширенное имя файла: toUpperCase является функцией в пакете Java.lang.String. Библиотеки Java могут (но не обязаны) быть реализованы как иерархические каталоги, где каждая функ­ция является файлом в каталоге для своего класса. Отметим, что иерархи­чность имен как бы вне языка; подпакет не имеет никаких особых привиле­гий при доступе к своему родителю. Здесь мы видим четкое отличие от пакетов-детей в Ada, которые имеют доступ к private-декларациям своих родителей при соблюдении правил, которые не позволяют экспортировать эти декларации.

Yandex.RTB R-A-252273-3
Yandex.RTB R-A-252273-4