Вам бонус- начислено 1 монета за дневную активность. Сейчас у вас 1 монета

3. Пакеты и интерфейсы

Лекция



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

  • Пакет и подпакет
  • Права доступа к членам класса
  • Размещение пакетов по файлам
  • Импорт классов и пакетов
  • Java-файлы
  • интерфейсы
  • Design patterns
  • Заключение

В стандартную библиотеку Java API входят сотни классов. Каждый программист в ходе работы добавляет к ним десятки своих. Множество классов становится необозримым. Уже давно принять классы объединять в библиотеки. Но библиотеки классов, кроме стандартной, не являются частью языка.

Разработчики Java включили в язык дополнительную конструкцию — паке-ты (packages). Все классы Java распределяются по пакетам. Кроме классов пакеты могут включать в себя интерфейсы и вложенные подпакеты(subpackages). Образуется древовидная структура пакетов и подпакедчэв.

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

Каждый пакет образует одно пространство имен(namespace). Это означает, что все имена классов, интерфейсов и подпакетов в пакете должны быть уникальны. Имена в разных пакетах могут совпадать, но это будут разные программные единицы. Таким образом, ни один класс, интерфейс или под-пакет не может оказаться сразу в двух пакетах. Если надо использовать два класса с одинаковыми именами из разных пакетов, то имя класса уточняется именем пакета: пакет.класс. Такое уточненное имя называетсяполным именем класса (fully qualified name).

Все эти правила, опять-таки, совпадают с правилами хранения файлов и подкаталогов в каталогах.

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

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

Как же создать пакет и разместить в нем классы и подпакеты?

Пакет и подпакет

Чтобы создать пакет надо просто в первой строке Java-файла с исходным кодом записать строку package имя;, например:

package mypack;

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

Имя подпакета уточняется именем пакета. Чтобы создать подпакет с именем, например, subpack, следует в первой строке исходного файла написать;

package mypack.subpack;

и все классы этого файла и всех файлов с такой же первой строкой попадут в подпакет subpack пакетаmypack.

Можно создать и подпакет подпакета, написав что-нибудь вроде

package mypack.subpack.sub;

и т. д. сколько угодно раз.

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

Компилятор Java может сам создать каталог с тем же именем mypack, a в нем подкаталог subpack, и разместить в них class-файлы с байт-кодами.

Полные имена классов А, в будут выглядеть так: mypack.A, mypack.subpack.в.

Фирма SUN рекомендует записывать имена пакетов строчными буквами, тогда они не будут совпадать с именами классов, которые, по соглашению, начинаются с прописной. Кроме того, фирма SUN советует использовать в качестве имени пакета или подпакета доменное имя своего сайта, записанное в обратном порядке, например:

com.sun.developer

До сих пор мы ни разу не создавали пакет. Куда же попадали наши файлы с откомпилированными классами?

Компилятор всегда создает для таких классов безымянный пакет (unnamed package), которому соответствует текущий каталог (current working directory)

файловой системы. Вот поэтому у нас class-файл всегда оказывался в том же каталоге, что и соответствующий Java-файл.

Безымянный пакет служит обычно хранилищем небольших пробных или промежуточных классов. Большие проекты лучше хранить в пакетах. Например, библиотека классов Java 2 API хранится в пакетах java, javax, org.omg. Пакет Java содержит только подпакеты applet, awt, beans, io, lang, math, net, rmi, security, sql, text, util и ни одного класса. Эти пакеты имеют свои подпакеты, например, пакет создания ГИП и графики java.awt содержит подпакеты color, datatransfer, dnd, event, font, geometry, im,image, print.

Конечно, состав пакетов меняется от версии к версии.

Права доступа к членам класса

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

Рассмотрим большой пример. Пусть имеется пять классов, размещенных в двух пакетах, как показано на рис. 3.1.

3. Пакеты и интерфейсы

Рис. 3.1. Размещение наших классов по пакетам

В файле Base.java описаны три класса: inpi, Base и класс Derivedpi, расширяющий класс вазе. Эти классы размещены в пакете pi. В классе Base определены переменные всех четырех типов доступа, а в методах f() классов inp1 и Derivedp1 сделана попытка доступа ко всем полям класса вазе. Неудачные попытки отмечены комментариями. В комментариях помещены сообщения компилятора. Листинг 3.1 показывает содержимое этого файла.

Листинг 3.1. Файл Base.java с описанием пакета p1

package p1;

class Inp1{

public void f () {

Base b = new Base();

// b.priv = 1; // "priv has private access in p1.Base"

b.pack = 1;

b.prot = 1;

b.publ = 1;

}

}

public class Base{

private int priv = 0;

int pack = 0;

protected int prot = 0;

public int publ = 0;

}

class Derivedpi extends Base{

public void f(Base a) {

// a.priv = 1; // "priv hds private access in pi.Base"

a.pack = 1;

a.prot = 1;

a.publ = 1;

// priv = 1; // "priv has private access in pi.Base"

pack = 1;

prot = 1;

publ = 1;

}

}

Как видно из листинга 3.1, в пакете недоступны только закрытые, private, поля другого класса.

В файле Inp2.java описаны два класса: inp2 и класс Derivedp2, расширяющий класс base. Эти классы находятся в другом пакете р2. В этих классах тоже сделана попытка обращения к полям класса вазе. Неудачные попытки прокомментированы сообщениями компилятора. Листинг 3.2 показывает содержимое этого файла.

Напомним, что класс вазе должен быть помечен при своем описании в пакете p1 модификатором public, иначе из пакета р2 не будет видно ни одного его члена.

Листинг 3.2. Файл Inp2.java с описанием пакета р2

package p2;

import pl.Base;

class Inp2{

public static void main(String[] args){

Base b = new Base();

// b.priv = 1; // "priv has private access in pl.Base"

// b.pack = 1; // "pack is not public in pl.Base;

// cannot be accessed from outside package"

// b.prot = 1; //„"prot has protected access in pi.Base"

b.publ = 1;

}

}

class Derivedp2 extends Base{

public void, f (Base a){

// a.priv = 1; // "priv has private access in. p1.Base"

// a.pack = 1; // "pack, is not public in pi.Base; cannot

//be accessed from outside package"

// a.prot = 1; // "prot has protected access in p1.Base"

a.publ = 1;

// priv = 1; // "priv has private access in pi.Base"

// pack = 1; // "pack is not public in pi.Base; cannot

// be accessed from outside package"

prot = 1;

publ = 1;

super.prot = 1;

}

}

Здесь, в другом пакете, доступ ограничен в большей степени.

Из независимого класса можно обратиться только к открытым, public, полям класса другого пакета. Из подкласса можно обратиться еще и к защищенным, protected, полям, но только унаследованным непосредственно, а не через экземпляр суперкласса.

Все указанное относится не только к полям, но и к методам. Подытожим все сказанное в табл. 3.1.

Таблица 3.1. Права доступа к полям и методам класса (область видимости)

Класс

Пакет

Пакет и подклассы

Все классы

private

+

"package"

+

+

protected

+

+

*

public

+

+

+

+

Особенность доступа к protected-полям и методам из чужого пакета отмечена звездочкой.

Размещение пакетов по файлам

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

Обратимся к тому же примеру. Об этом говорит сайт https://intellect.icu . Пусть в каталоге D:\jdkl.3\MyProgs\ch3 есть пустой подкаталог classes и два файла — Base.java и Inp2.java, — содержимое которых показано в листингах 3.1 и 3.2. Рис. 3.2 демонстрирует структуру каталогов уже после компиляции.

Мы можем проделать всю работу вручную.

1. В каталоге classes создаем подкаталоги р! и р2.

2. Переносим файл Base.java в каталог р! и делаем р] текущим каталогом.

3. Компилируем Base.java, получая в каталоге р! три файла: Base.class, Inpl.class, Derivedpl.class.

4. Переносим файл Inp2java в каталог р2.

5. Снова делаем текущим каталог classes.

6. Компилируем второй файл, указывая путь p2\Inp2.java.

7. Запускаем программу java p2.inp2.

Вместо шагов 2 и 3 можно просто создать три class-файла в любом месте, а потом перенести их в каталог pi. В class-файлах не хранится никакая информация о путях к файлам.

Смысл действий 5 и 6 в том, что при компиляции файла Inp2.java компилятор уже должен знать классp1.Base, а отыскивает он файл с этим классом по пути p1.Base.class, начиная от текущего каталога.

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

Если использовать ключи (options) командной строки компилятора, то можно выполнить всю работу быстрее.

1. Вызываем компилятор с ключом -d путь, указывая параметром путь начальный каталог для пакета:

javac -d classes Base.java

Компилятор создаст в каталоге classes подкаталог р1 и поместит туда три class-файла.

2. Вызываем компилятор с еще одним ключом -classpath путь, указывая параметром путь каталог classes, в котором находится подкаталог с уже откомпилированным пакетом pi:

javac -classpath classes -d classes Inp2.java

Компилятор, руководствуясь ключом -d, создаст в каталоге classes подкаталог р2 и поместит туда два class-файла, при создании которых он "заглядывал" в каталог pi, руководствуясь ключом -classpath.

3. Делаем текущим каталог classes.

4. Запускаем профамму java p2.inp2.

3. Пакеты и интерфейсы

Рис. 3.2. Структура каталогов

3. Пакеты и интерфейсы

Рис. 3.3. Протокол компиляции и запуска программы

Для "юниксоидов" все это звучит, как музыка, ну а прочим придется вспомнить MS DOS.

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

На рис. 3.2 отображена структура каталогов после компиляции.

На рис. 3.3 показан вывод этих действий в окно Command Prompt и содержимое каталогов после компиляции.

Импорт классов и пакетов

Внимательный читатель заметил во второй строке листинга 3.2 новый оператор import. Для чего он нужен?

Дело в том, что компилятор будет искать классы только в -одном пакете, именно, в том, что указан в первой строке файла. Для классов из другого пакета надо указывать полные имена. В нашем примере они короткие, и мы могли бы писать в листинге 3.2 вместо Base полное имя p1.Base.

Но если полные имена длинные, а используются классы часто, то стучать по клавишам, набирая полные имена, становится утомительно. Вот тут-то мы и пишем операторы import, указывая компилятору полные имена классов.

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

Это тоже может стать утомительным и тогда используется вторая форма оператора import — указывается имя пакета или подпакета, а вместо короткого имени класса ставится звездочка *. Этой записью компилятору предписывается просмотреть весь пакет. В нашем примере можно было написать

import p1.*;

Напомним, что импортировать можно только открытые классы, помеченные модификатором public.

Внимательный читатель и тут настороже. Мы ведь пользовались методами классов стандартной библиотеки, не указывая ее пакетов? Да, правильно.

Пакет java.iang просматривается всегда, его необязательно импортировать. Остальные пакеты стандартной библиотеки надо указывать в операторах import, либо записывать полные имена классов.

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

Знатокам C/C++

Оператор import не эквивалентен директиве препроцессора include — он не подключает никакие файлы.

Java-файлы

Теперь можно описать структуру исходного файла с текстом программы на языке Java.

  • В первой строке файла может быть необязательный оператор package.
  • В следующих строках могут быть необязательные операторы import.
  • Далее идут описания классов и интерфейсов.

Еще два правила.

  • Среди классов файла может быть только один открытый public-класс.
  • Имя файла должно совпадать с именем открытого класса, если последний существует.

Отсюда следует, что, если в проекте есть несколько открытых классов, то они должны находиться в разных файлах.

Соглашение "Code Conventions" рекомендует открытый класс, который, если он имеется в файле, нужно описывать первым.

Интерфейсы

Вы уже заметили, что получить расширение можно только от одного класса, каждый класс в или с происходит из неполной семьи, как показано на рис. 3.4, а. Все классы происходят только от "Адама", от класса object. Но часто возникает необходимость породить класс о от двух классов вис, как показано на рис. 3.4, б. Это называется множественным наследованием (multiple inheritance). В множественном наследовании нет ничего плохого. Трудности возникают, если классы вис сами порождены от одного класса А, как показано на рис. 3.4* в. Это так называемое "ромбовидное" наследование.

3. Пакеты и интерфейсы

Рис. 3.4. Разные варианты наследования

В самом деле, пусть в классе А определен метод f (), к которому мы обращаемся из некоего метода класса о. Можем мы быть уверены, что метод f о выполняет то, что написано в классе А, т. е. это метод A.f о? Может, он переопределен в классах в и с? Если так, то каким вариантом мы пользуемся: B.f() или c.f()? Конечно, можно определить экземпляры классов и обращаться к методам этих экземпляров, но это совсем другой разговор.

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

Создатели языка Java после долгих споров и размышлений поступили радикально — запретили множественное наследование вообще. При расширении класса после слова extends можно написать только одно имя суперкласса. С помощью уточнения super можно обратиться только к членам непосредственного суперкласса.

Но что делать, если все-таки при порождении надо использовать несколько предков? Например, у нас есть общий класс автомобилей Automobile, от которого можно породить класс грузовиков Truck и класс легковых автомобилей Саг. Но вот надо описать пикап Pickup. Этот класс должен наследовать свойства и грузовых, и легковых автомобилей.

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

Интерфейс (interface), в отличие от класса, содержит только константы и заголовки методов, без их реализации.

Интерфейсы размещаются в тех же пакетах и подпакетах, что и классы, и компилируются тоже в class-файлы.

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

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

Затем, в фигурных скобках, записываются в любом порядке константы и заголовки методов. Можно сказать, что в интерфейсе все методы абстрактные, но слово abstract писать не надо. Константы всегда статические, но слова static и final указывать не нужно.

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

Вот какую схему можно предложить для иерархии автомобилей:

interface Automobile{ . . . }

interface Car extends Automobile{ . . . }

interface Truck extends Automobile{ . . . }

interface Pickup extends Car, Truck{ . . . }

Таким образом, интерфейс — это только набросок, эскиз. В нем указано, что делать, но не указано, как это делать.

Как же использовать интерфейс, если он полностью абстрактен, в нем нет ни одного полного метода?

Использовать нужно не интерфейс, а его реализацию (implementation). Реализация интерфейса — это класс, в котором расписываются методы одного или нескольких интерфейсов. В заголовке класса после его имени или после имени его суперкласса, если он есть, записывается слово implements и, через запятую, перечисляются имена интерфейсов.

Вот как можно реализовать иерархию автомобилей:

interface Automobile{ . . . }

interface Car extends Automobile! . . . }

class Truck implements Automobile! . . . }

class Pickup extends Truck implements Car{ . . . }

или так:

interface Automobile{ . . . }

interface Car extends Automobile{ . . . }

interface Truck extends Automobile{ . . . }

class Pickup implements Car, Truck{ . . . }

Реализация интерфейса может быть неполной, некоторые методы интерфейса расписаны, а другие — нет. Такая реализация — абстрактный класс, его обязательно надо пометить модификатором abstract.

Как реализовать в классе pickup метод f(), описанный и в интерфейсе саг, и в интерфейсе Truck с одинаковой сигнатурой? Ответ простой — никак. Такую ситуацию нельзя реализовать в классе Pickup. Программу надо спроектировать по-другому.

Итак, интерфейсы позволяют реализовать средствами Java чистое объектно-ориентированное проектирование, не отвлекаясь на вопросы реализации проекта.

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

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

Листинг 3.3 показывает, как можно собрать с помощью интерфейса хор домашних животных из листинга 2.2.

Листинг 3.3. Использование интерфейса для организации полиморфизма

interface Voice{

void voice();

}

class Dog implements Voice{

public void voice (){

System.out.println("Gav-gav!");

}

}

class Cat implements Voice{

public void voice (){

System.out.println("Miaou!");

}

}

class Cow implements Voice{

public void voice(){

System.out.println("Mu-u-u!");

}

}

public class Chorus{

public static void main(String[] args){

Voiced singer = new Voice[3];

singer[0] = new Dog();

singer[1] = new Cat();

singer[2] = new Cow();

for(int i = 0; i < singer.length; i++)

singer[i].voice();

}

}

Здесь используется интерфейс voice вместо абстрактного класса Pet, описанного в листинге 2.2.

Что же лучше использовать: абстрактный класс или интерфейс? На этот вопрос нет однозначного ответа.

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

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

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

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

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

Листинг 3.4. Система управления светофором

interface Lights{

int RED = 0;

int YELLOW = 1;

int GREEN = 2;

int ERROR = -1;

}

class Timer implements Lights{

private int delay;

private static int light = RED;

Timer(int sec)(delay = 1000 * sec;}

public int shift(){

int count = (light++) % 3;

try{

switch(count){

case RED: Thread.sleep(delay); break;

case YELLOW: Thread.sleep(delay/3); break;

case GREEN: Thread.sleep(delay/2); break;

}

}catch(Exception e){return ERROR;}

return count;

}

}

class TrafficRegulator{

private static Timer t = new Timer(1);

public static void main(String[] args){

for (int k = -0; k < 10; k++)

switch(t.shift()){

case Lights.RED: System.out.println("Stop!"); break;

case Lights.YELLOW: System.out.println("Wait!"); break;

case Lights.GREEN: System.out.println("Go!"); break;

case Lights.ERROR: System.err.println("Time Error"); break;

default: System.err.println("Unknown light."); return;

}

}

}

Здесь, в интерфейсе Lights, определены константы, общие для всего проекта.

Класс Timer реализует этот интерфейс и использует константы напрямую как свои собственные. Методshift о этого класса подает сигналы переключения светофору с разной задержкой в зависимости от цвета. Задержку осуществляет метод sleep() класса Thread из стандартной библиотеки, которому передается время задержки в миллисекундах. Этот метод нуждается в обработке исключений try{} catch() {}, о которой мы будем говорить в главе 16.

Класс TrafficReguiator не реализует интерфейс Lights и пользуется полными именами Lights.RED и т.д. Это возможно потому, что константы RED, YELLOW и GREEN по умолчанию являются статическими.

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

Design patterns

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

Нет ли подобных общих методов в программировании? Есть.

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

Естественно спроектировать такую автоматизированную систему из трех частей.

  • Первая часть, назовем ее Контроллером (controller), принимает сведения от датчиков и преобразует их в какую-то единообразную форму, пригодную для дальнейшей обработки, например, приводит к одному масштабу. При этом для каждого датчика надо написать свой модуль, на вход которого поступают сигналы конкретного устройства, а на выходе образуется унифицированная информация.
  • Вторая часть, назовем ее Моделью (model), принимает эту унифицированную информацию от Контроллера, ничего не зная о датчике и не интересуясь тем, от какого именно датчика она поступила, и преобразует ее по своим алгоритмам опять-таки к какому-то однообразному виду, например, к последовательности чисел.
  • Третья часть системы, Вид (view), непосредственно связана с устройствами вывода и преобразует поступившую от Модели последовательность чисел в график, диаграмму или пакет для отправки по сети. Для каждого устройства придется написать свой модуль, учитывающий особенности именно этого устройства.

В чем удобство такой трехзвенной схемы? Она очень гибка. Замена одного датчика приведет к замене только одного модуля в Контроллере, ни Модель, ни Вид этого даже не заметят. Надо представить прогноз в каком-то новом виде, например, для телевидения? Пожалуйста, достаточно написать один модуль и вставить его в Вид. Изменился алгоритм обработки данных? Меняем Модель.

Эта схема разработана еще в 80-х годах прошлого столетия [То есть XX века. — Ред.] в языке Smalltalk и получила название MVG (Model-View-Controller). Оказалось, что она применима во многих областях, далеких от метеорологии, всюду, где удобно отделить обработку от ввода и вывода информации.

Сбор информации часто организуется так. На экране дисплея открывается поле ввода, в которое вы набиваете сведения, допустим, фамилии в произвольном порядке, а в соседнем поле вывода отображается обработанная информация, например, список фамилий по алфавиту. Будьте уверены, что эта программа организована по схеме МУС. Контроллером служит поле ввода, Видом — поле вывода, а Моделью — метод сортировки фамилий. В третьей части книги мы рассмотрим примеры реализации этой схемы.

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

Вот, пожалуй, самая простая из этих схем. Надо написать класс, у которого можно создать только один экземпляр, но этим экземпляром должны пользоваться объекты других классов. Для решения этой задачи предложена схема Singleton, представленная в листинге 3.5.

Листинг 3.5. Схема Singleton

final class Singleton{

private static Singleton s = new Singleton(0);

private int k;

private Singleton(int i){k = i;}

public static Singleton getReference()(return s;}

public int getValue(){return k;}

public void setValue(int i){k = i;}

}

public class SingletonTest {

public static void main(String[] args){

Singleton ref = Singleton.getReference();

System.out.println(ref.getValue());

ref.setValue(ref.getValue() + 5);

System.out.println(ref.getValue());

}

}

Класс singleton окончательный — его нельзя расширить. Его конструктор закрытый — никакой метод не может создать экземпляр этого класса. Единственный экземпляр s класса singleton — статический, он создается внутри класса. Зато любой объект может получить ссылку на экземпляр методом getReference (), Изменить состояние экземпляра s методом setValue() или просмотреть его текущее состояние методомgetValue().

Это только схема — класс singleton надо еще наполнить полезным содержимым, но идея выражена ясно и полностью.

Схемы проектирования были систематизированы и изложены в книге [7]. Четыре автора этой книги были прозваны "бандой четырех" (Gang of Four), а книга, коротко, "GoF". Схемы обработки информации получили название "Design Patterns". Русский термин еще не устоялся. Говорят о "шаблонах", "схемах разработки", "шаблонах проектирования".

В книге GoF описаны 23 шаблона, разбитые на три группы:

1. Шаблоны создания объектов: Factory, Abstract Factory, Singleton, Builder, Prototype.

2. Шаблоны структуры объектов: Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy.

3. Шаблоны поведения объектов: Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template, Visitor.

Описания даны, в основном, на языке C++. В книге [8] те же шаблоны представлены на языке Java. Той же теме посвящено электронное издание [9]. В книге [10] подробно обсуждаются вопросы разработки систем на основе design patterns.

Мы, к сожалению, не можем разобрать подробно design patterns в этой кни-те. Но каждый программист начала XXI века должен их знать. Описание многих разработок начинается словами: "Проект решен на основе шаблона", и структура проекта сразу становится ясна для всякого, знакомого с design patterns.

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

Заключение

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

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

Примечание

В C++ изначально было сделано — friend-функции
А вот дальше пошло хуже, но хоть как-то развивалось:

  • в Delphi «протекали» private-поля внутри модуля, потом протечки залепили с помощью strict protected;
  • в Java protected-поля протекают внутри пакета,
  • но потом появился ее близнец C#, в котором protected не протекает, а для контролируемых протечек внутри сборки придумали internal.

К сожалению, в одной статье не просто дать все знания про пакеты. Но я - старался. Если ты проявишь интерес к раскрытию подробностей,я обязательно напишу продолжение! Надеюсь, что теперь ты понял что такое пакеты, интерфейсы и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Объектно-ориентированное программирование ООП

Ответы на вопросы для самопроверки пишите в комментариях, мы проверим, или же задавайте свой вопрос по данной теме.

создано: 2014-10-09
обновлено: 2021-03-13
132552



Рейтиг 9 of 10. count vote: 2
Вы довольны ?:


Поделиться:

Найди готовое или заработай

С нашими удобными сервисами без комиссии*

Как это работает? | Узнать цену?

Найти исполнителя
$0 / весь год.
  • У вас есть задание, но нет времени его делать
  • Вы хотите найти профессионала для выплнения задания
  • Возможно примерение функции гаранта на сделку
  • Приорететная поддержка
  • идеально подходит для студентов, у которых нет времени для решения заданий
Готовое решение
$0 / весь год.
  • Вы можите продать(исполнителем) или купить(заказчиком) готовое решение
  • Вам предоставят готовое решение
  • Будет предоставлено в минимальные сроки т.к. задание уже готовое
  • Вы получите базовую гарантию 8 дней
  • Вы можете заработать на материалах
  • подходит как для студентов так и для преподавателей
Я исполнитель
$0 / весь год.
  • Вы профессионал своего дела
  • У вас есть опыт и желание зарабатывать
  • Вы хотите помочь в решении задач или написании работ
  • Возможно примерение функции гаранта на сделку
  • подходит для опытных студентов так и для преподавателей



Комментарии


Оставить комментарий
Если у вас есть какое-либо предложение, идея, благодарность или комментарий, не стесняйтесь писать. Мы очень ценим отзывы и рады услышать ваше мнение.
To reply

Объектно-ориентированное программирование ООП

Термины: Объектно-ориентированное программирование ООП