Эффективное получение атрибутов объекта или принудительное объявление атрибута класса
УСТАНОВКА ФОНА
Я пытаюсь создать библиотеку для доступа и кэширования данных веб-службы в Android и натолкнулся на проблему.
Все объекты, которыми управляет моя библиотека, наследуются от базы Entity
учебный класс. Любой производный класс Entity
может объявить другие поля * или атрибуты *.
Базовый класс отвечает за возврат Entity
атрибуты, которые должны быть прочитаны из кэша (SQLite или File) или из веб-службы (REST или SOAP). В моей текущей реализации Entity
класс выполняет это с помощью отражения: он читает все имена полей класса, помеченные @Attribute
аннотаций.
ПРОБЛЕМА
Проблема, с которой я сталкиваюсь в своей реализации, заключается в следующем: каждый раз, когда я запрашиваю все Entity
атрибуты с использованием функции, как static Set<String> getAttributes()
эта функция должна создать Set
реализация (в настоящее время используется HashSet
для этого для быстрого поиска).
Я хотел бы избежать выделения и инициализации Set<String>
каждый раз делается запрос на все атрибуты.
С моей точки зрения набор атрибутов специфичен для всего Entity
класс, а не Entity
объект. То есть: имея class Customer extends Entity
, все Customer
экземпляры имеют одинаковые точные атрибуты - у каждого есть имя, адрес и так далее.
Моя текущая попытка - объявить static Set<String> attributes
в каждом классе, который распространяется Entity
и инициализировать это Set
используя отражение в классе static
блок, как это:
class Customer extends Entity
{
private static final Set<String> attributes = new HashSet<String>();
static
{
Entity.populateAttributes(Customer.class);
}
}
Учитывая класс для инициализации, Entity
класс может искать все поля, отмеченные @Attribute
аннотации в этом классе и его базовых классах (например, Customer extends Person
а также Person extends Entity
заполнит Customer.attributes
установить с атрибутами, объявленными для Customer
класс и те, которые унаследованы от Person
учебный класс).
У меня проблема в том, что attributes
набор не может быть определен для класса, который расширяется Entity
и я хотел бы обеспечить это во время компиляции.
Я видел, как это делается для Serializable
интерфейс в Eclipse: когда создается класс, который реализует Serializable
Eclipse показывает предупреждение, если ваш класс не объявляет [private] static final long serialVersionUID
,
ВОПРОС
Есть ли способ, которым я применяю это Serializable
поведение для моего Entity
Класс и показать предупреждение или (лучше) ошибку, если класс не объявил поле?
Есть ли другой подход к возвращению имен атрибутов для Entity
класс?
СНОСКА
* Я использовал термин field
для свойств объекта, которые не должны управляться библиотекой и термином attribute
для свойств объекта, которые должны управляться библиотекой (считываться из веб-службы или кэша SQLite/ файла и сохраняться в веб-службе или кэше SQLite/ файла)
РЕДАКТИРОВАТЬ 1
По сути, я пытаюсь добиться набора Entity
атрибуты * (см. сноску выше) эффективным способом. Этот список используется вспомогательными классами для хранения значений объектов в базе данных (CREATE TABLE
запросы могут быть выведены из имен и типов атрибутов) или отправлены на веб-сервис.
Эта библиотека используется для кэширования значений из веб-службы и для синхронизации локальной базы данных (которая может содержать дополнительные пользовательские входные значения и может отсутствовать обновленные значения сервера для объектов) с данными, доступными через веб-службу. Он не предназначен для замены использования аксессоров / мутаторов для каждого поля в приложении с универсальными аксессорами / мутаторами.
Эта концепция известна как Key-Value Coding и используется многими платформами и библиотеками. Например, первые два примера библиотек, использующих KVC, которые я обнаружил при поиске в Google, - это Cocoa и Sproutcore. Ссылки: документация для разработчиков Apple и Sproutcore wiki.
KVC также используется в разработке Android. Bundle
, SQLiteCursor
а также ContentValues
интенсивно использовать KVC.
1 ответ
Поскольку я, возможно, не смогу обеспечить объявление статического поля в определении производных классов, я буду хранить карту наборов атрибутов и описаний классов в определении Entity
класс, описанный выше, и убедитесь, что набор атрибутов для производного класса инициализируется в Entity
конструктор.
В качестве примера:
public class Entity
{
private final static Map<Class<? extends Entity>, Set<String>> attributes = new HashMap<Class<? extends Entity>, Set<String>>();
public static void populateAttributes(Class<? extends Entity> derivedClass)
{
//initialize the set of attributes for the derived class and
//add it to attributes map with "derivedClass" as key
}
static
{
populateAttributes(Entity.class);
}
public Entity()
{
//calling this.getClass() returns the object's actual (derived) class(*)
if(!attributes.containsKey(this.getClass())
populateAttributes(this.getClass());
}
//rest of class definition (including getAttributes method)
}
public class Customer extends Entity
{
@Attribute
String someAttribute; //will be processed automatically
}
Стоимость получения Entity
Атрибуты s сводятся к разбору всех атрибутов класса и созданию нового набора для их хранения в операции проверки и извлечения Map
который должен быть довольно маленьким при использовании HashMap
,
Стоимость создания Entity
экземпляр увеличивается путем проверки атрибутов Map
(быстро HashMap
с). Стоимость инициализации attributes
набор для данного класса незначителен, поскольку это делается только один раз для каждого производного типа класса.
Учитывая, что атрибуты запрашиваются по крайней мере один раз для каждого экземпляра класса в 90% или более случаях, это должно дать лучшую общую производительность, чем первоначальное решение, описанное в вопросе.
(*) Призвание this.getClass()
в базовом классе экземпляр метода вернет фактический класс объекта. Если объект был инициализирован как экземпляр производного класса, описание производного класса (Class
объект) будет возвращен. Вопрос об этом уже задавался и на него отвечали: какой класс getClass() сообщает в конструкторе базового класса.