Создание типа экземпляра одной переменной таким же, как у другого, программирование с использованием интерфейсов - PullRequest
3 голосов
/ 07 ноября 2011

Я писал код, который имеет дело с заголовками HTTP-ответов (неизменяемая коллекция после заполнения), и обнаружил, что код такой:

private Map<String,String> headers;

public ctor() {
    this.headers = new Hashtable<String,String>();
    // ... some more ... (actually, this fills this.headers based on ctor parameters)
}

public Map<String,String> getResponseHeaders() {
    Map<String,String> temp = new Hashtable<String,String>();
    temp.putAll(this.headers);
    return temp;
}

Глядя на это, мне пришло в голову, что, хотя я знаю тип headers сейчас , и, по общему признанию, рассматриваемый класс достаточно короткий (всего около 50 строк в настоящее время и не готов к росту). гораздо больше) что в данном конкретном случае это не главная проблема, если бы проблемное пространство было немного более сложным, то в getResponseHeaders() я мог бы не знать тип, который был this.headers (для использования имен из этого конкретного примера) экземпляр для. Кроме того, в большом классе, где я хочу возвращать копии коллекций, отслеживая количество различных переменных-членов экземпляра и их типы (возможно, зависит от ряда факторов; размер списка приходит на ум как один возможный рассмотрение) может стать довольно волосатым.

Два связанных вопроса:

Без полноценной структуры внедрения зависимостей и полного запрета использования отражения (из-за снижения производительности) есть ли способ сделать тип экземпляра temp таким же, как тип экземпляра this.headers в коде, как выше, для общего случая?

Есть ли ситуации, в которых это реально может иметь большое значение?

1 Ответ

2 голосов
/ 07 ноября 2011

Вы можете позвонить this.headers.clone(), но вам нужно разыграть результат.Также это работает только в тех случаях, когда тип является клонируемым, и клон делает именно то, что вам нужно (например, в данном случае мелкий клон).

Кроме этого, нет возможности доступа к типу времени выполнения.(то, что вы называете типом экземпляра) this.headers уже будет включать отражение.Однако я не стал бы воздерживаться от использования рефлексии только потому, что кто-то сказал, что она медленная.Не все отражающие операции выполняются медленно (например, я ожидаю, что вызов getClass() для объекта будет довольно быстрым), и не все выполняемые вами операции будут влиять на производительность вашего приложения.Это зависит от гораздо большего количества факторов, т. Е. От того, как часто выполняется эта операция, насколько хорош оптимизатор и т. Д.

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

Итак, подумайте об этом: Действительно ли вам нужно убедиться, что это точно такой же тип времени выполнения? Обычно это не так.Весь смысл программирования с использованием интерфейсов заключается в том, что обычно вам не нужно заботиться о реальном типе среды выполнения, а только о том, что он реализует правильный интерфейс (Map здесь).Таким образом, геттер в его текущей форме будет в порядке, даже если в будущем тип времени выполнения this.headers на самом деле будет TreeMap.

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

Это можно сделать очень легко, изменив метод получения на

return java.util.Collections.unmodifiableMap(this.headers);

Обратите внимание, что таким образом вызывающие абоненты будут видеть изменениякарта, если вы измените this.headers после того, как getResponseHeaders был вызван.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...