Как ограничить ключ и его значение в HashMap с помощью обобщений? - PullRequest
2 голосов
/ 14 февраля 2012

У меня есть иерархия классов, где, скажем, класс ICommon находится в корне.У меня есть отдельные реализации репозиториев, чтобы манипулировать объектами, принадлежащими на каждом уровне в этой иерархии.

interface IRepository<T extends ICommon> {
   public void createOrUpdate(T toCreate);
}

Теперь я хочу сохранить карту классов против их репозиториев.Это та часть, которую я не могу понять.

Я попробовал это, и это работает, но я не думаю, что это правильное представление.

private Map<Class<? extends ICommon>, IRepository<? extends ICommon>> repoMap = new   
   HashMap<Class<? extends ICommon>, IRepository<? extends ICommon>>();

Позже клиенты называют этометод для получения соответствующего экземпляра хранилища.

public <T extends ICommon> IRepository<T> getRepository(Class<T> clazz) {
   return (IRepository<T>) repoMap.get(clazz);
}

1 Ответ

1 голос
/ 14 февраля 2012

Я столкнулся с подобной проблемой некоторое время назад, и, как правило, нет способа ограничить ключ и значение в карте, однако можно построить карту безопасным способом. Если вы введете еще один метод для возврата хранилища целевого класса, вы получите проверку времени компиляции (к сожалению, вы не можете сделать это во время выполнения, так как генерируется универсальный тип). После использования этого метода вы можете зарегистрировать все репозитории. Это может быть неявный способ - когда владелец хранилища знает обо всех хранилищах, или путем изучения пути к классам для классов с реализованным интерфейсом IRepository, или, если вы используете контейнер IoC (например, Spring), вы можете получить эти классы автоматически подключенными. В любом случае, простой Java-решение ниже:

interface IRepository<T extends ICommon> {
    public void createOrUpdate(T toCreate);

    public Class<T> getTargetClass();
}

class Repository1 implements IRepository<Common1> {

    @Override
    public void createOrUpdate(Common1 toCreate) {
        //no-op
    }

    @Override
    public Class<Common1> getTargetClass() {
        return Common1.class;
    }
}

class Repository2 implements IRepository<Common2> {

    @Override
    public void createOrUpdate(Common2 toCreate) {
        //no-op
    }

    @Override
    public Class<Common2> getTargetClass() {
        return Common2.class;
    }
}

class RepositoryHolder<T extends ICommon> {

    private IRepository repository1 = new Repository1();
    private IRepository repository2 = new Repository2();
    //...

    private Map<Class<T>, IRepository> map = new HashMap<Class<T>, IRepository>() {{
        put(repository1.getTargetClass(), repository1);
        put(repository2.getTargetClass(), repository2);
        //...
    }};

    public IRepository<T> getRepository(Class<T> clazz) {
        return map.get(clazz);
    }
}
...