簡體   English   中英

如何注冊實現相同接口的類的對象

[英]How to register objects of classes implementing the same 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實現都可以在一個中央位置注冊自己,然后可以通過一個公共點進行訪問,如上所述

我還沒有測試過,但是這樣的事情怎么樣。 使用類作為鍵在地圖中注冊映射器。 一個更完整的實現將使用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);
    }
}

或通過提供類,使映射方法“減少魔力”,如您的代碼中一樣(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-或兩個Maps…

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

您正在重新實現Guava的BiMap 用那個

1)如何在運行時獲取適當的mapper實現,並知道要調用的方法(map或mapReverse)。

要在運行時瀏覽元級別的信息,可以嘗試使用Reflectons之類的東西。

它允許您在運行時“查詢”類定義元數據:

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

因此,用於查找正確的Mapper實現的查找表可以是動態的。 但是請確定這種方法的優缺點。 特別是您將如何維護課程。

2)如果Mapper實現分散在不同的Java項目中,我該如何創建一個框架,使每個Mapper實現都可以在一個中央位置注冊自己,然后可以通過一個公共點進行訪問,如上所述

如果最終程序是所有這些子項目的集成(即編譯為一個),則除了使用上述方法掃描類路徑之外,無需執行任何特殊操作。 否則,如果這些子項目在單獨的環境中運行(遠程),則您必須探索更多方法。

所以最近我自己用spring解決了這個問題。 這是解決方案

首先,將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();
    }
}

因此,現在您不必關心映射器類是什么,也不需要自己在一些初始化代碼中注冊它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM