1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-thinking-in-java-zh

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
16.8 RTTI真的有害吗.md 9.1 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 11.03.2025 09:15 d56454c

16.8 RTTI действительно вредна?

Различные паттерны дизайна, представленные в этой главе, стремятся избежать использования RTTI, что может создать впечатление, будто RTTI является чем-то негативным (вспомните бедный goto, который был так плохо воспринят, что его вообще не включили в Java). Однако это не всегда верно. Более точно можно сказать, что неправильное использование RTTI "вредно". Мы стараемся избегать использования RTTI потому, что её ошибочное применение может привести к снижению расширяемости системы. Нашей целью было обеспечить возможность свободного добавления новых типов в систему с минимальным воздействием на окружающий код. Поскольку RTTI часто используется неправильно (например, когда она используется для поиска всех типов в системе), это значительно снижает способность кода к расширению — при добавлении нового типа требуется найти все места, где используется RTTI. Даже если вы пропустите один такой случай, компилятор вам не поможет.Однако сам RTTI не создаёт автоматически неконсистентный код. Вспомним пример с автоматической очисткой мусора. На этот раз мы добавляем новый инструмент, который я называю TypeMap. Он содержит Hashtable (ассоциативный массив), содержащий несколько Vector'ов, но интерфейс очень простой: можно добавить (add()) новый объект, а также получить (get()) Vector, содержащий все объекты определённого типа. Ключевой особенностью этого паттерна является то, что TypeMap динамически добавляет новые типы при встрече с ними. Таким образом, каждый раз, когда новый тип добавляется в систему (даже во время выполнения программы), он будет корректно обрабатываться.Наш пример основан на структуре типа Trash внутри "пакета" (Package) c16.Trash (и использует тот же файл Trash.dat).

//: DynaTrash.java
// Использование ассоциативного массива Vector и RTTI
// для автоматического сортирования мусора в
// векторах. Этот подход, несмотря на использование RTTI,
// является расширяемым.
package c16.dynatrash;
import c16.trash.*;
import java.util.*;
// Общий TypeMap работает в любой ситуации:
class TypeMap {
  private Hashtable t = new Hashtable();
  public void add(Object o) {
    Class type = o.getClass();
    if(t.containsKey(type))
      ((Vector)t.get(type)).addElement(o);
    else {
      Vector v = new Vector();
      v.addElement(o);
      t.put(type,v);
    }
  }
  public Vector get(Class type) {
    return (Vector)t.get(type);
  }
  public Enumeration keys() { return t.keys(); }
  // Возвращает обработчик адаптерного класса для возможности
  // обратного вызова из ParseTrash.fillBin():
  public Fillable filler() {
    // Анонимный внутренний класс:
    return new Fillable() {
      public void addTrash(Trash t) { add(t); }
    };
  }
}
```Пожалуйста, учтите, что использование `Hashtable`, `Vector` и `Enumeration` является устаревшим в современной Java. Рекомендую использовать более новые коллекции, такие как `HashMap`, `ArrayList` и `Iterator`. Хотя функционал очень мощный, но определение `TypeMap` довольно простое. Оно просто включает хэш-таблицу, а метод `add()` выполняет большую часть работы. При добавлении нового типа объект класса `Class` извлекается. Затем с помощью этого объекта проверяется, существует ли вектор (`Vector`), содержащий объекты данного типа, в хэш-таблице. Если такой вектор уже существует, он извлекается, и новый объект добавляется в него; если нет, то объект класса `Class` и новый пустой вектор добавляются как пара "ключ-значение".Метод `keys()` позволяет получить список всех объектов класса `Class`, а метод `get()` позволяет получить соответствующий вектор по объекту класса.

Метод `filler()` представляет интерес, так как он использует дизайн метода `ParseTrash.fillBin()`. Он может попытаться заполнить вектор, а также использовать метод `addTrash()` для заполнения любого объекта, который реализует интерфейс `Fillable`.

Для создания такого вызова метод `filter()` просто возвращает ссылку на объект, который реализует интерфейс `Fillable`, и передает эту ссылку в качестве параметра методу `fillBin()`, как показано ниже:

```java
ParseTrash.fillBin("Trash.dat", bin.filler());
```

Чтобы создать этот вызов, мы использовали "анонимный внутренний класс" (описанный в главе 7). Поскольку нам не требуется имя класса для реализации интерфейса `Fillable`, достаточно иметь ссылку на объект этого класса, использование анонимного внутреннего класса здесь вполне уместно.

Одной из особенностей этого дизайна является то, что хотя контроль над категориями не был предусмотрен, каждый раз при выполнении метода `fillBin()` объект класса `Trash` автоматически добавляется в контейнер `bin`.После просмотра предыдущих примеров большинство частей класса `DynaTrash` должны быть вам знакомыми. На этот раз вместо помещения новых объектов класса `Trash` в векторы типа `bin`, мы используем механизм внутренней классификации `TypeMap`. Процесс прохождения через `TypeMap` и операция со всеми отдельными векторами оказывается довольно простым делом.

Перебор ключей происходит следующим образом:```java
Перечисление ключей = бин.ключи();
пока(ключи.естьЕщеЭлементы()) {
  Trash.суммаЗначения(бин.получить((Класс)ключи.следующийЭлемент()));
}
```

Как видно, добавление новых типов в систему никак не влияет на эти коды, а также не затрагивает код `TypeMap`. Это явно является наиболее полным решением проблемы. Хотя этот подход действительно сильно зависит от RTTI, стоит отметить, что каждый ключ-значение в хэш-таблице проверяет только один тип. Кроме того, при добавлении нового типа мы не оказываемся в ситуации "забывчивости" относительно добавления правильного кода в систему, так как вообще ничего добавлять не требуется.
```

Опубликовать ( 0 )

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

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-thinking-in-java-zh.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-thinking-in-java-zh.git
oschina-mirror
wizardforcel-thinking-in-java-zh
wizardforcel-thinking-in-java-zh
master