Главная » Java » Работа с интерфейсами Java

0

в предыдущей главе мы рассмотрели класс Attr и показали, каким образом он может быть расширен с целью получения специализированных версий атрибутов. Теперь все, что нам нужно, – это получить возможность сопоставления атрибутов реальным объектам.

Первое решение, которое надлежит принять, относится к вопросу, целесообразно ли факт принадлежности атрибутов объекту отображать в структуре типа, Которому объект принадлежит. Объект сам по себе способен, если вы того пожелаете, содержать набор атрибутов, открытый для доступа. Вы также вправе оговорить, что способность хранения атрибутов в объекте – это "заслуга" соответствующего типа, которая должна быть зафиксирована в иерархии типов. Оба Подхода вполне правомерны. Мы, однако, полагаем, что стратегия, предусматривающая "объявление" способности к хранению атрибутов на уровне типа, окажется более продуктивной. Ниже мы создадим общий тип Attributed, предна3liаченный для получения объектов, которые могут быть помечены атрибутами.

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

класс, более, по их мнению, полезный. Мы поступим иначе – представим Attributed в форме интерфейса:

public interface Attributed {

void add(Attr newAttr);

Attrfind(String attrName);

Attr remove(String attrName);

java.util .Iterator attrs();

}

Интерфейс содержит заголовки четырех методов: add предназначен для добавления в объект Attributed нового атрибута; find позволяет определить, существует ли в составе объекта атрибут с заданным именем; remove предназначен для удаления указанного атрибута; attrs возвращает список атрибутов, присоединенных к объекту, с помощью средств интерфейса Iterator, который находит применение в классах коллекций. Интерфейс java.util.Iterator подробно

рассмотрен в главе 17.

Реализация интерфейсов

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

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

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

В качестве примера рассмотрим простую реализацию интерфейса Attributed, которая предусматривает использование средств прикладного класса java.util.HashMap. В объявлении класса AttributedImpl содержится предложение implementsAttributed, означающее, что класс обязан реализовать все методы интерфейса Attributed. Класс AttributedImpl реализует методы интерфейса с помощью средств стандартного класса HashMap (за более подробной информацией о классе HashMap обращайтесь к разделу 16.7.1 на странице 455). Позже мы применим подобное решение в процессе реализации интерфейса Attributed для получения других объектов, нуждающихся в добавлении атрибутов. Вот как выглядит объявление класса AttributedImpl:

import java.util.*;

class AttributedImpl implements Attributed { protected HashMap attrTable = new HashMap();

public void add(Attr newAttr) {

attrTable.put(newAttr.getName(), newAttr);

}

public Attr find(String name) {

                         return (Attr)attrTable.get(name); }

public Attr remove(String name) {

 return (Attr)attrTable,remove(name);

}

public Iterator attrs() {

return attrTable.values().iterator();

}

}

инициализатор поля AttrTable создает объект типа HashMap, предназначенный для хранения набора атрибутов. Объект, на который указывает AttrTable, выполняет большую часть работы. Класс HashMap использует метод hashCode объектов-ключей для их хеширования. Класс String содержит хорошую реализацию метода hashCode, поэтому необходимости в применении какого-либо другого метода, способного генерировать хеш-код, нет.

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

Метод attrs возвращает объект типа Iterator, который помогает просматривать набор объектов-атрибутов. Iterator – это интерфейсный тип, определенный в пакете java. uti 1 и предназначенный для использования в классах коллекций, подобных HashMap (за информацией обращайтесь к разделу 16.2 на странице 438). Тот же тип используется и в нашем примере – он обеспечивает стандартные способы просмотра содержимого коллекций. В составе класса AttributedImpl определено поле коллекции AttrTable, поэтому мы и воспользовались обычным средством доступа к содержимому коллекции – типом Iterator. Применение типа Iterator обеспечивает и другое преимущество: гораздо легче реализовать интерфейс Attributed, используя именно стандартный класс коллекции, такой как HashMap, в котором как раз и поддерживаются объекты Iterator.

Использование реализации интерфейсов

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

При использовании такого рода композиции каждый метод класса, наследующего интерфейс, обращается к соответствующей реализации метода в объекте другого класса. Ниже приведена еще одна реализация интерфейса Attributed, в которой для построения версии класса Body, поддерживающей атрибуты, применяется объект класса Attri butedImpl.

import java.util.Iterator;

class AttributedBody extends Body implements Attributed {

private AttributedImpl attrImpl = new AttributedImpl();

public AttributedBody() {

super();

}

public AttributedBody(String name, Body orbits) {

super(name, orbits); }

// доступ к методам Attributed с помощью объекта attrImpl public void add(Attr newAttr)

{ attrImpl.add(newAttr); }

public Attr find(String name)

{ return attrImpl.find(name); }

public Attr remove(String name)

{ return attrImpl.remove(name); }

public Iterator attrs()

{ return attrImpl.attrs(); }

}

Класс AttributedBody, как гласит его контракт, расширяет класс Body и реализует интерфейс Attributed. Реализация всех методов класса Body наследуется. Каждый метод интерфейса Attributed реализуется в классе AttributedBody посредством обращения к одноименному методу объекта класса Attr; butedImpl с возвратом полученного значения (если таковой предусмотрен в объявлении AttributedImpl). Понятно, что в составе класса AttributedBody в этом случае должно присутствовать поле типа AttributedImpl, которое следует корректно проинициализировать ссылкой на созданный объект того же типа.

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

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

По теме:

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