Эффективное получение атрибутов объекта или принудительное объявление атрибута класса

УСТАНОВКА ФОНА

Я пытаюсь создать библиотеку для доступа и кэширования данных веб-службы в 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() сообщает в конструкторе базового класса.

Другие вопросы по тегам