русс | укр

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

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

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

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


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

Идиома «метод-адаптер»


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


Что делать, если у вас имеется существующий класс, реализующий Iterable, и вы хотите добавить новые способы использования этого класса в синтаксисе foreach? Допустим, вы хотите иметь возможность выбора между перебором списка слов в прямом или обратном направлении. Если просто воспользоваться наследованием от класса и переопределить метод iterator, то существующий метод будет заменен и никакого выбора не будет. Одно из решений этой проблемы основано на использовании идиомы, которую я называю «методом-адаптером». Термин «адаптер» происходит от одноименного паттерна: вы должны предоставить интерфейс, необходимый для работы синтаксиса foreach. Если у вас имеется один интерфейс, а нужен другой, проблема решается написанием адаптера. В данном случае требуется добавить к стандартному «прямому» итератору обратный, так что переопределение исключено. Вместо этого мы добавим метод, создающий объект Iterable, который может использоваться в синтаксисе foreach. Как будет показано далее, это позволит нам предоставить несколько вариантов использования foreach:

//: holding/AdapterMethodIdiom.java

// Идиома "метод-адаптер" позволяет использовать foreach

// с дополнительными разновидностями Iterable.

import java.util.*;

 

class ReversibleArrayList<T> extends ArrayList<T> {

public ReversibleArrayList(Collection<T> c) { super(c); }

public Iterable<T> reversed() {

return new Iterable<T>() {

public Iterator<T> iterator() {

return new Iterator<T>() {

int current = size() - 1;

public boolean hasNext() { return current > -1; }

public T next() { return get(current--); }

public void remove() { // // He реализован

throw new UnsupportedOperationException();

}

};

}

};

}

}

 

public class AdapterMethodIdiom {



public static void main(String[] args) {

ReversibleArrayList<String> ral =

new ReversibleArrayList<String>(

Arrays.asList("To be or not to be".split(" ")));

// Получаем обычный итератор, полученный при помощи iterator():

for(String s : ral)

System.out.print(s + " ");

System.out.println();

// Передаем выбранный нами Iterable

for(String s : ral.reversed())

System.out.print(s + " ");

}

}

<spoiler text="Output:">

To be or not to be

be to not or be To

</spoiler> Если просто поместить объект ral в синтаксис foreach, мы получим (стандартный) «прямой» итератор. Но если вызвать для объекта reversed(), поведение изменится. Использовав этот прием, можно добавить в пример IterableClass.java два метода-адаптера:

//: holding/MultiIterableClass.java

// Adding several Adapter Methods.

import java.util.*;

 

public class MultiIterableClass extends IterableClass {

public Iterable<String> reversed() {

return new Iterable<String>() {

public Iterator<String> iterator() {

return new Iterator<String>() {

int current = words.length - 1;

public boolean hasNext() { return current > -1; }

public String next() { return words[current--]; }

public void remove() { He реализован

throw new UnsupportedOperationException();

}

};

}

};

}

public Iterable<String> randomized() {

return new Iterable<String>() {

public Iterator<String> iterator() {

List<String> shuffled =

new ArrayList<String>(Arrays.asList(words));

Collections.shuffle(shuffled, new Random(47));

return shuffled.iterator();

}

};

}

public static void main(String[] args) {

MultiIterableClass mic = new MultiIterableClass();

for(String s : mic.reversed())

System.out.print(s + " ");

System.out.println();

for(String s : mic.randomized())

System.out.print(s + " ");

System.out.println();

for(String s : mic)

System.out.print(s + " ");

}

}

<spoiler text="Output:">

banana-shaped. be to Earth the know we how is that And

is banana-shaped. Earth that how the be And we know to

And that is how we know the Earth to be banana-shaped.

</spoiler> Из выходных данных видно, что метод Collections.shuffle не изменяет исходный массив, а только переставляет ссылки в shuffled. Так происходит только потому, что метод randomized() создает для результата Arrays.asList() «обертку» в виде ArrayList. Если бы операция выполнялась непосредственно с объектом List, полученным от Arrays.asList(), то это привело бы к изменению нижележащего массива:

//: holding/ModifyingArraysAsList.java

import java.util.*;

 

public class ModifyingArraysAsList {

public static void main(String[] args) {

Random rand = new Random(47);

Integer[] ia = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

List<Integer> list1 =

new ArrayList<Integer>(Arrays.asList(ia));

System.out.println("До перестановки : " + list1);

Collections.shuffle(list1, rand);

System.out.println("После перестановки : " + list1);

System.out.println("Массив: " + Arrays.toString(ia));

 

List<Integer> list2 = Arrays.asList(ia);

System.out.println("До перестановки : " + list2);

Collections.shuffle(list2, rand);

System.out.println("После перестановки : " + list2);

System.out.println("Массив: " + Arrays.toString(ia));

}

}

<spoiler text="Output:">

До перестановки : [1, 2, 3. 4, 5. 6. 7. 8, 9, 10]

После перестановки : [4. 6, 3, 1. 8. 7, 2, 5. 10. 9]

Массив: [1, 2. 3. 4. 5. 6. 7, 8. 9. 10]

До перестановки : [1, 2. 3, 4, 5. 6. 7. 8, 9, 10]

После перестановки : [9. 1. 6. 3. 7, 2. 5, 10, 4. 8]

Массив: [9. 1, 6. 3. 7, 2, 5. 10. 4. 8]

</spoiler> В первом случае вывод Arrays.asList() передается конструктору ArrayList(), а последний создает объект ArrayList, ссылающийся на элементы ia. Перестановка этих ссылок не изменяет массива. Но, если мы используем результат Arrays.asList(ia) напрямую, перестановка изменит порядок ia. Важно учитывать, что Arrays.asList() создает объект List, который использует нижележащий массив в качестве своей физической реализации. Если с этим объектом List выполняются какие-либо изменяющие операции, но вы не хотите изменения исходного массива, создайте копию в другом контейнере.

Резюме

В Java существует несколько способов хранения объектов:

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

· В Collection хранятся отдельные элементы, а в Map — пары ассоциированных элементов. Механизм параметризации позволяет задать тип объектов, хранимых в контейнере, поэтому поместить в контейнер объект неверного типа невозможно, и элементы не нуждаются в преобразовании типа при выборке. И Collection, и Map автоматически изменяются в размерах при добавлении новых элементов. В контейнерах не могут храниться примитивы, но механизм автоматической упаковки автоматически создает объектные «обертки», сохраняемые в контейнере.

· В контейнере List, как и в массиве, объектам назначаются числовые индексы — таким образом, массивы и List являются упорядоченными контейнерами.

· Используйте ArrayList при частом использовании произвольного доступа к элементам или LinkedList при частом выполнении операций вставки и удаления в середине списка.

· Поведение очередей и стеков обеспечивается контейнером LinkedList.

· Контейнер Map связывает с объектом не целочисленный индекс, а другой объект. Контейнеры HashMap оптимизированы для быстрого доступа, а контейнер TreeMap хранит ключи в отсортированном порядке, но уступает по скорости HashMap. В контейнереLinkedHashMap элементы хранятся в порядке вставки, но хеширование обеспечивает быстрый доступ.

· В контейнере Set каждый объект может храниться только в одном экземпляре. Контейнер HashSet обеспечивает максимальную скорость поиска, а в TreeSet элементы хранятся в отсортированном порядке. В контейнере LinkedHashSet элементы хранятся в порядке вставки.

· Использовать старые классы Vector, Hashtable и Stack в новом коде не нужно.

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


 



<== предыдущая лекция | следующая лекция ==>
Синтаксис foreach и итераторы | Глава 12 ОБРАБОТКА ОШИБОК И ИСКЛЮЧЕНИЙ


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


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

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

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


 


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

 
 

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

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