Чтение онлайн

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

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

Повторное

использование

классов

Возможность повторного использования

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

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

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

Второй способ гораздо интереснее. Новый класс создается как специализация уже существующего класса. Взяв существующий класс за основу, вы добавляете к нему свой код без изменения существующего класса. Этот механизм называется наследованием (inheritance), и большую часть работы в нем совершает компилятор. Наследование является одним из «краеугольных камней» объект-но-ориентированного программирования; некоторые из его дополнительных применений описаны в главе 8.

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

у

и

Синтаксис композиции

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

// reusing/SprinklerSystem java

// Композиция для повторного использования кода.

class WaterSource { private String s, WaterSourceO {

System out println( "WaterSourceO"); s = "сконструирован";

}

public String toStringO { return s; }

}

public class SprinklerSystem {

private String valvel. valve2, valve3, valve4, private WaterSource source = new WaterSourceO; private int i. private float f, public String toStringO { return

"valvel = " + valvel + " " + • "valve2 = " + valve2 + " " + "valve3 = " + valve3 + " " +

"valve4 = " + valve4 + "\n" +

••-j = - + -j + •• + -f = •• + f + •• " +

"source = " + source,

}

public static void main(String[] args) {

SprinklerSystem sprinklers = new SprinklerSystem, System out println(sprinklers);

}

} /* Output-WaterSourceO

valvel = null valve2 = null valve3 = null valve4 = null i = 0 f = 0.0 source =

сконструирован *///•-

В обоих классах определяется особый метод toString. Позже вы узнаете, что каждый не-примитивный объект имеет метод toString, который вызывается в специальных случаях, когда компилятор располагает не объектом, а хочет получить его строковое представление в формате String. Поэтому в выражении из метода S р ri n klerSyste m.toStri n g :

"source = " + source;

компилятор видит, что к строке "source = " «прибавляется» объект класса WaterSource. Компилятор не может это сделать, поскольку к строке можно «добавить» только такую же строку, поэтому он преобразует объект source в String, вызывая метод toString. После этого компилятор уже в состоянии соединить две строки и передать результат в метод System.out.println (или статическим методам print и printnb, используемым в книге). Чтобы подобное поведение поддерживалось вашим классом, достаточно включить в него метод toString.

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

Компилятор не создает объекты для ссылок «по умолчанию», и это логично, потому что во многих случаях это привело бы к лишним затратам ресурсов. Если вам понадобится проинициализировать ссылку, сделайте это самостоятельно:

• в точке определения объекта. Это значит, что объект всегда будет инициализироваться перед вызовом конструктора;

• в конструкторе данного класса;

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

• с использованием инициализации экземпляров.

В следующем примере продемонстрированы все четыре способа:

//: reusing/Bath.java

// Инициализация в конструкторе с композицией.

import static net.mindview.util.Print.*:

class Soap {

private String s: SoapO {

printCSoapO"); s = "Constructed";

}

public String toStringO { return s: }

}

public class Bath {

private String // Инициализация в точке определения-si = "Счастливый", s2 = "Счастливый", s3. s4. private Soap castille; private int i; private float toy; public BathO {

print( В конструкторе BathO"), s3 = "Радостный"; toy = 3.14f; ч castille = new SoapO;

}

// Инициализация экземпляра-

{ i = 47; }

public String toStringO {

if(s4 == null) // Отложенная инициализация-s4 = "Радостный";

return

"si = " + si + "\n" + "s2 = " + s2 + "\n" + "s3 = " + s3 + "\n" + "s4 = " + s4 + "\n" + Hi = " + i + "\n" + "toy = " + toy + "\n" + "castille = " + castille;

}

public static void main(String[] args) { Bath b = new Bath О; print(b);

}

} /* Output; В конструкторе Bath О SoapO

Поделиться с друзьями: