1. Зачем поле softMap объявлено protected? Даже если нужен доступ у наследников (в данном случае я думаю не нужен) лучше написать модификатор private и добавить protected метод getCache
2. Потенциальный NPE в методе get(): не сихронизованы методы clear() и get(). Более подробно: cointaisKey() возвращает true, вызывается метод clear(), get() от Map возвращает null.
Решение без synchronized: внутри метода Cache#get() использовать сразу Map#get() и проверять результат на null. В таком случае нужно поле Map нужно делать private и запрещать любые доступы к нему извне
Возможно в вашем случае это не критично, но для других пользователей этого кода может стать проблемой.
Спасибо за наводку, про Resources.getIdentifier(), не знал — посмотрю. Насчёт макарон, пожалуйста, поподробнее — есть реальный проект, где всё приведённое выше использовалось. Можете ткнуть в куски кода, которые по вашему мнению написаны не очень хорошо — обсудим. Ссылка на проект — в конце статьи.
1. initCaptions() проходит только по R.string
2. Ничего затратного тут нет — что-то мне подсказывает, что вытягивание статических полей класса их значений — это очень быстрая операция (Кстати, а как вы думаете как реализовано связывание strings.xml и R.string внутри андроид ядра? Мне кажется тоже с использованием такого подхода).
3. Хранение тоже довольно дёшево — там же просто строки
4. Да, случай специфичен, но иногда нужна знать и использовать его.
где ключ — внешний идентификатор сообщения, значение — внутренний идентификатор (значение поля в R.class).
Как вы будете инициализировать данный Map? Отвечу за вас — вы будете писать что-то наподобие следующего:
map.put("msg_01", R.string.msg_01);
map.put("msg_02", R.string.msg_02);
// and so on
Какие минусы:
1. При добавлении нового сообщения вам нужно будет не забыть добавить строчку инициализации Map'а
2. При числе сообщений over 9000 вам придётся иметь over 9000 строк инициализации Map.
Моё решение — динамическое и оно избавляет нас от минусов привидённых выше.
Мне вот не понятно — за что минусы. Я описал конкретный случай, когда использвание R.class не очень удобно.
И я не говорю, что так нужно делать всегда. Я говорю, что есть разные способы решения поставленной задачи. Чтобы это понять достаточно было зайти в мой репозитарий на github и посмотреть реальный код.
Кстати, программисты андроид платформы — тоже не боги, достаточно взглянуть на их issue tracker. Моё мнение (как и мнение некоторых моих коллег) такое, что R.class — вообще довольно спорная штука.
Может быть да, а может быть и нет. Мне не нравится, когда в коде пестрит R.class.
Кстати, есть конкретный пример, когда можно использовать данный подход: есть андроид приложение, есть сторонняя библиотека. Эта самая библиотека может, например, выбрасывать exception (который, кстати, может вообще не знать, что он в контексте андроида), хранящий в себе некий идентификационный номер сообщения. Приложение должно как-то локализовать (в смысле — перевести) данное сообщение и вывести на экран. Первый вариант, который приходит в голову — switch на все возможные варианты:
if ( e.getMessageId().equals("msg_001") ) {
context.getString(R.strings.msg_001);
} else if ( ... ) {
// and other dozens
}
Строго говоря, это не совсем singleton, т.к. теоретически он может быть проинстанцирован несколько раз. Я даже не знаю гарантированно ли конструктор android.app.Application будет вызван один раз — доки молчат.
1. Зачем поле softMap объявлено protected? Даже если нужен доступ у наследников (в данном случае я думаю не нужен) лучше написать модификатор private и добавить protected метод getCache
2. Потенциальный NPE в методе get(): не сихронизованы методы clear() и get(). Более подробно: cointaisKey() возвращает true, вызывается метод clear(), get() от Map возвращает null.
Решение без synchronized: внутри метода Cache#get() использовать сразу Map#get() и проверять результат на null. В таком случае нужно поле Map нужно делать private и запрещать любые доступы к нему извне
Возможно в вашем случае это не критично, но для других пользователей этого кода может стать проблемой.
2. Ничего затратного тут нет — что-то мне подсказывает, что вытягивание статических полей класса их значений — это очень быстрая операция (Кстати, а как вы думаете как реализовано связывание strings.xml и R.string внутри андроид ядра? Мне кажется тоже с использованием такого подхода).
3. Хранение тоже довольно дёшево — там же просто строки
4. Да, случай специфичен, но иногда нужна знать и использовать его.
где ключ — внешний идентификатор сообщения, значение — внутренний идентификатор (значение поля в R.class).
Как вы будете инициализировать данный Map? Отвечу за вас — вы будете писать что-то наподобие следующего:
Какие минусы:
1. При добавлении нового сообщения вам нужно будет не забыть добавить строчку инициализации Map'а
2. При числе сообщений over 9000 вам придётся иметь over 9000 строк инициализации Map.
Моё решение — динамическое и оно избавляет нас от минусов привидённых выше.
И я не говорю, что так нужно делать всегда. Я говорю, что есть разные способы решения поставленной задачи. Чтобы это понять достаточно было зайти в мой репозитарий на github и посмотреть реальный код.
Кстати, программисты андроид платформы — тоже не боги, достаточно взглянуть на их issue tracker. Моё мнение (как и мнение некоторых моих коллег) такое, что R.class — вообще довольно спорная штука.
Кстати, есть конкретный пример, когда можно использовать данный подход: есть андроид приложение, есть сторонняя библиотека. Эта самая библиотека может, например, выбрасывать exception (который, кстати, может вообще не знать, что он в контексте андроида), хранящий в себе некий идентификационный номер сообщения. Приложение должно как-то локализовать (в смысле — перевести) данное сообщение и вывести на экран. Первый вариант, который приходит в голову — switch на все возможные варианты:
Мой вариант предлагает
Красиво? Мне кажется — да.