2015-10-01 5 views
2

Я пытаюсь запрограммировать вид реестра для объектов разных классов.TreeMap с классами как ключ

У меня есть следующий:

public interface DbObject{ 
    void setId(long id); 
    Long getId(); 
} 

прототипический класс, реализующий этот интерфейс будет следующий:

public class BasicDbObject implements DbObject{ 
    private long id=null; 
    void setId(long id){ 
     this.id=id; 
    } 
    Long getId(){ 
     return id; 
    } 
} 

Я хочу построить различные различные Реализации этого интерфейса. И я хочу иметь объект Map, который отображает из каждого класса реализации в Map экземпляров.

Что-то вроде этого:

Map <Class<C implements DbObject> , Map<Long, C>> registry = new TreeMap/HashMap/SomeOtherKindOfMap (...) 

Я знаю, что я мог бы сделать что-то вроде

Map <String,Map<Long,DbObjects>> registry = new ... 

Но этот путь я должен был бы написать еще некоторый код для определения имен, сравнивая классы и так далее. Есть ли более простой способ сделать это?

Так что я хочу знать: возможно ли иметь объекты класса в виде ключей на карте дерева?

Каким будет синтаксис объявления объекта карты, который отображает от реализации классов C к объектам карты каждое сопоставление от длинного объекта (id) к экземплярам C?

Я хочу, чтобы иметь возможность делать запросы, как следующее:

BasicObject bo = registry.get(BasicObject.class).get(42); 

assuing идентификатор сделал

BasicObject bo=new BasicObject(...); 
innerMap = new SomeMap<Long,BasicObject>(); 
innerMap.put(42,bo); 
registry.put(BasicObject.class,innerMap); 

раньше.

Скажите, пожалуйста, если это еще не ясно, мне трудно объяснить, так как английский не мой родной язык.

Заранее спасибо.


Edit:

Оказывается, я могу сделать что-то очень близко к тому, что я хочу, определяя общий класс по карте:

public class ObjectRegistry <T extends DbObject>{ 

    private HashMap<Class<T>, TreeMap<Long,T>> registry=null; 

    ObjectRegistry(){ 
     registry=new HashMap<Class<T>, TreeMap<Long,T>>(); 
    } 
    public void register(T dbObject){ 
     TreeMap<Long, T> map = registry.get(dbObject.getClass()); 
     if (map==null){ 
      map=new TreeMap<Long,T>(); 
      registry.put((Class<T>) dbObject.getClass(),map); 
     } 
     map.put(dbObject.getId(),dbObject); 
    } 

    public <T extends DbObject>T get(Class<T> objectClass,long id){ 
     TreeMap<Long, T> map = (TreeMap<Long, T>) registry.get(objectClass); 
     if (map != null){ 
      return map.get(id); 
     } 
     return null; 
    } 

    public TreeMap<Long,T> getAll(Class<T> dbObjectClass) { 
     return registry.get(dbObjectClass); 
    } 
} 

Я использую TreeMap для внутренние сопоставления, так как я хочу легко вернуть экземпляры классов, отсортированные по id.

Так утонченный вопрос: Есть ли способ сделать это, без предложения <T extends DbObject> в главе класса?


Edit 2:

снова Думая через него, оказывается, что ответ Джона является именно решение этой проблемы.

Вот мой окончательный код:

HashMap<Class<? extends DbObject>, TreeMap<Long, ? extends DbObject>> registry = null; 

public <T extends DbObject> T get(Class<T> clazz, long id) { 
    TreeMap<Long, T> map = (TreeMap<Long, T>) registry.get(clazz); 
    if (map != null) { 
     return map.get(id); 
    } 
    return null; 
} 

public <T extends DbObject> void register(T dbObject) { 
    TreeMap<Long, T> map = (TreeMap<Long, T>) registry.get(dbObject.getClass()); 
    if (map == null) { 
     map = new TreeMap<Long, T>(); 
     registry.put((Class<T>) dbObject.getClass(), map); 
    } 
    map.put(dbObject.getId(), dbObject); 
} 


public <T extends DbObject> TreeMap<Long, T> getAll(Class<T> dbObjectClass) { 
    return (TreeMap<Long, T>) registry.get(dbObjectClass); 
} 

Он не нуждается в пункте в голове класса <T extends DbObject>.

ответ

3

Так что я хочу знать: возможно ли иметь объекты класса в виде ключей на карте деревьев?

TreeMap зависит от наличия в общей сложности порядка над ключевым пространством, как это установлено с помощью ключа типа, имеющего естественный порядок (путем осуществления Comparable) или с помощью отдельного Comparator объекта, который вы предоставляете. Class es не имеют естественного порядка. Вполне возможно, что вы могли бы написать подходящий Comparator, но это кажется мне очень ухищренным.

Но зачем вам нужно TreeMap? Вы не описали никаких требований, которые, по крайней мере, не были бы адресованы другим типом Map. В частности, я почти всегда нахожу HashMap лучшим выбором, и я не вижу причин, почему это было бы неподходящим в этом. В качестве ключей могут иметь объекты типа Class.

Кроме того, если вам действительно не нужна какая-либо конкретная реализация, тогда вам лучше всего объявление типа просто как Map. Таким образом, вы можете обеспечить любую реализацию Map и даже изменить то, что вы предоставляете, если вы когда-нибудь обнаружите причину этого.

Каким будет синтаксис объявления объекта карты, который отображает от реализации классов C к объектам карты каждое сопоставление от длинного объекта (id) к экземплярам C?

Вы спрашиваете, что ограничения на тип каждого значения зависят от типа связанного ключа, но нет способа объявить тип, который обеспечивает такую ​​взаимосвязь. Является ли конкретный ключ или конкретное значение подходящим для Map, является функцией типа карты, а не типа друг друга.

Вы можете создавать общие методы вокруг доступа к вашей карте, которые обеспечивают внешний вид того, что вы хотите, но методы извлечения данных должны будут выполняться. Например:

Map<Class<? extends DbObject>, Map<Long, ? extends DbObject>> registry = /*...*/; 

<T extends DbObject> Map<Long, T> getRegistryMap(Class<T> clazz) { 
    return (Map<Long, T>) registry.get(clazz); 
} 

<T extends DbObject> T get(Class<T> clazz, Long id) { 
    Map<Long, T> map = getRegistryMap(clazz); 

    return (map == null) ? null : map.get(id); 
} 

<T extends DbObject> T put(Class<T> clazz, Long id, T obj) { 
    Map<Long, T> map = getRegistryMap(clazz); 

    if (map == null) { 
     map = new HashMap<>(); 
     registry.put(clazz, map); 
    } 
    return map.put(id, obj); 
} 

Обновлено добавить:

Так уточненный вопрос: Есть ли способ сделать это без оговорки <T extends DbObject> в голове класса?

Да, что я уже писал. Просто удалите простую декларацию класса. Вам не нужен общий класс для создания общих методов. Фактически, эти два ортогональны. Обычный метод универсального класса может использовать параметры типа этого класса. Это не делает их универсальными методами. Метод является общим, если он объявляет своим собственным параметром (типами), как это показано выше.Ваш метод get() также делает это, и важно понимать, что параметр типа <T>, который вы явно указываете в сигнатуре метода, теняет параметр типа класса с тем же именем: он отличается от T.

+0

Это не о treemap, я мог бы использовать другие виды карт, я знаю. Речь идет о синтаксисе объявления карты. –

+0

@StephanRichter, ответьте обновленно, чтобы ответить на ваш уточненный вопрос. –

+0

Хорошо, это в основном то, что я хотел знать. Я оставлю его открытым в течение нескольких дней, возможно, у кого-то есть лучшая идея/обходное решение/что-то еще. Если нет, я буду отмечать ваш ответ как правильный в следующие дни. Спасибо, до сих пор. –

Смежные вопросы