如何注册实现相同接口的类的对象

时间:2015-11-23 04:26:06

标签: java interface

我有一个用于映射java bean的接口

public interface Mapper <K,V> {
    K map(V v);
    V mapReverse(K k);
}

实施示例

public class CarMapper implements Mapper<Car, CarDTO> {
    public Car map(CarDTO dto) {
         //implementation
    };

    public CarDTO mapReverse(Car car) {
         //implementation
    };
}

现在我想为所有这些实现提供一个公共访问点,以便用户不必记住所有实现的名称。

例如: -

public class MapperFacade {
    public static<K,V> K map(V v, Class<K> k, Class<V> v) {
        //1) get the appropriate mapper implementation (throw an exception if no such implementation is  found)
        //2) map the object
        //3) return the object
    }
}

现在我有两个问题: -

1)如何在运行时获得适当的mapper实现并知道要调用哪个方法(map或mapReverse)。

2)如果Mapper实现分布在不同的java项目中,我如何创建一个框架,其中每个mapper实现可以在中心位置注册自己,然后可以通过上面提到的公共点访问

4 个答案:

答案 0 :(得分:0)

我还没有测试过这个但是这样的事情怎么样。使用类作为键在映射中注册映射器。更完整的实现将使用isAssignable检查,而不仅仅是精确的类匹配。如果映射的值是基类的子类。

public class MapperFacade<K,V> implements Mapper<K,V> {
    private Map<Class<K>,Mapper<K,V>> keyMappers = new HashMap<Class<K>,Mapper<K,V>>();
    private Map<Class<V>,Mapper<K,V>> valueMappers = new HashMap<Class<V>,Mapper<K,V>>();

    public void addMapper(Mapper<K,V> mapper, Class<K> keyClass, Class<V> valueClass) {
        keyMappers.put(keyClass, mapper);
        valueMappers.put(valueClass, mapper);
    }

    public K map(V value) {
        Mapper<K,V> mapper = valueMappers.get(value.getClass());
        return mapper.map(value);
    }

    public V mapReverse(K key) {
        Mapper<K,V> mapper = keyMappers.get(key.getClass());
        return mapper.mapReverse(key);
    }
}

或制作地图方法&#34;不那么神奇&#34;通过提供类,如在代码中(MapperFacade不再实现Mapper)

    public K map(V value, Class<V> valueClass) {
        Mapper<K,V> mapper = valueMappers.get(valueClass);
        return mapper.map(value);
    }

    public V mapReverse(K key, Class<V> keyClass) {
        Mapper<K,V> mapper = keyMappers.get(keyClass);
        return mapper.mapReverse(key);
    }

这假定每个类有一个映射器。如果同一个类可能有多个映射器,则可能需要使用单个HashMap,而是使用由Class<K>Class<V>组成的键的bean - 或者两个地图映射...

    private Map<Class<K>,Map<Class<V>,Mapper<K,V>>> keyMappers = ...
    private Map<Class<V>,Map<Class<K>,Mapper<K,V>>> valueMappers = ...

答案 1 :(得分:0)

你正在重新实现番石榴的BiMap。使用它。

答案 2 :(得分:0)

  

1)如何在运行时获得适当的映射器实现   知道调用哪个方法(map或mapReverse)。

要在运行时探索元级别信息,您可以尝试Reflectons

之类的内容

它允许您查询&#34;运行时的类定义元数据:

Reflections reflections = new Reflections("my.project");
Set<Class<? extends SomeType>> subTypes = reflections.getSubTypesOf(SomeType.class);

因此,用于查找Mapper的正确实现的查找表可以是动态的。但请确保这种方法的优缺点。特别是你将如何维护课程。

  

2)如果Mapper实现分布在不同的java上   项目,我如何创建每个mapper实现的框架   可以在中心位置注册,然后可以通过访问   如上所述的共同点

如果最终程序是所有这些子项目的集成(即编译为一个),那么除了使用上述方法扫描类路径之外,没有什么特别需要做的。否则,如果这些子项目在不同的环境(远程)中运行,那么您必须探索more approaches.

答案 3 :(得分:0)

所以我最近用弹簧解决了这个问题。 这是解决方案

首先,将Mapper接口重构为: -

public abstract class Mapper <Entity, DTO> {
    private static final MapperFactory mapperFactory = MapperFactory.getInstance();
    public Mapper() {
        mapperFactory.registerMapper(getEntityClass(), getDTOClass(),this);
    }

    public abstract Entity map(DTO object);
    public abstract DTO mapReverse(Entity object); 

    public abstract Class<Entity> getEntityClass();
    public abstract Class<DTO> getDTOClass();
}

public class MapperFactory {
    private Map<String, Mapper> mappers = new ConcurrentHashMap<>(); //MapperFactory is a singleton class, ConcurrentHashMap ensures thread safety.         

    private static final MapperFactory INSTANCE = new MapperFactory();

    public static MapperFactory() {
        return MapperFactory.INSTANCE;
    }

    public <Entity, DTO> void registerMapper(Class<Entity> entityClass, Class<DTO> dtoClass, Mapper<Entity, DTO> mapper) {
        mappers.put(dtoClass.getCanonicalName(), mapper);
        mappers.put(entityClass.getCanonicalName(), mapper);
    }

    public <T> Mapper getMapper(Class<T> sourceClass) {
         mappers.get(sourceClass.getCanonicalName());
    }
}

对于访问所有映射器的通用接口,请使用以下类: -

public class MapperFacade {
    private MapperFactory mapperFactory = MapperFactory.getInstance();

    public <Entity, DTO> DTO entityToDTO(Entity entity, Class<DTO> dtoClass) {
        Mapper<Entity, DTO> mapper = mapperFactory.getMapper(entity.getClass());
        return mapper.mapReverse(entity);
    }

    public <Entity, DTO> Entity dtoToEntity(DTO dto, Class<Entity> entityClass) {
        Mapper<Entity, DTO> mapper = mapperFactory.getMapper(dto.getClass());
        return mapper.map(dto);
    }
}

现在,对于自动注册任何映射器,我们可以使用spring的@Component注释。例如: -

@Component
public class CarMapper <Car, CarDTO> {
    public Car map(CarDTO carDTO) {
        //impl
    }

    public CarDTO mapReverse(Car car) {
        //impl
    }

    public Class<Car> getEntityClass() {
        return Car.getClass();
    }
    public Class<CarDTO> getDtoClass() {
        return CarDTO.getClass();
    }
}

所以现在你不必关心映射器类是什么,也不需要在一些初始化代码中自己注册它们。