简体   繁体   中英

How to restrict a key and its value in a HashMap using generics?

I have a class hierarchy, where, say, class ICommon is at the root. I have separate repositories implementations in order to manipulate objects belonging at each level in this hierarchy.

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

Now, I want to maintain a Map of classes VS their repositories. Its this part which I can't figure out.

I tried this, which works, but I do not think it is the correct representation.

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

Later on, clients call this method to get an appropriate repository instance.

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

I faced similar problem some time ago and generally there is not way to restrict key and value in map, however it is possible to construct map in typesafe way. If you introduce one more method for returning target class repository you'll get compile time checking(unfortunately you can't do this in runtime since generic type is raised). After you have this method you can register all repositories. It could be either implicit way - when repository holder know about all repositories, or by exploring classpath for classes with IRepository interface implemented, or if you use IoC container (like spring) you can get those classes autowired. Anyway, plain java solution is below:

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM