Java-映射具有循环依赖关系的DTO

时间:2019-05-27 16:01:27

标签: java design-patterns circular-dependency

当前设置经典的映射器,将实体转换为DTO。 一些实体(因此还有DTO)互相引用(在特定的JPA实体定义之后)。

让我们说:

public class Person {
  private String name;
  private List<State> states; // All states with this person
  // Getters & Setters
}

public class State {
  private String name;
  private List<Person> persons; // All persons with this state
   // Getters & Setters
}

有了这样的循环依赖项,我必须像这样设置映射器:

public class PersonMapper {
   public PersonDTO toDTO(Person p) { // not null
     PersonDTO dto = new PersonDTO();
     dto.setName(p.getName());
     dto.setStates(p.States().stream().map(stateMapper::toDTO).collect(Collectors.toList());
     return dto;
   }

public class StateMapper {
   public StateDTO toDTO(State s) { // not null
     StateDTO dto = new StateDTO();
     dto.setName(s.getName()); 
     dto.setPersons(s.getPersons().stream().map(personMapper::toDTO).collect(Collectors.toList());
     return dto;
   }

一种容易避免这种情况的方法是在PersonMapper或StateMapper中创建一个新方法,并使其不映射人员或州。但是我想知道是否存在一种已知的设计模式或更通用的方法?

谢谢

1 个答案:

答案 0 :(得分:0)

唯一的方法是首先构造一个侧面:

public class PersonMapper {
   public PersonDTO toDTO(Person p) { // not null
     PersonDTO dto = new PersonDTO();
     dto.setName(p.getName());
     dto.setStates(new ArrayList<>());
     states.forEach(state -> state.getPersons().add(dto)) //todo: uniqueness check
     return dto;
   }
}

public class StateMapper {
   //todo: maybe Person.name is better than the whole Person object in the map
   public StateDTO toDTO(State s, Map<Person, PersonDTO> personMapping) { 
     StateDTO dto = new StateDTO();
     dto.setName(s.getName()); 

     List<PersonDTO> persons = s.getPersons().stream().map(personMapping::get)
                               .collect(Collectors.toList();
     persons.forEach(p -> p.getStates().add(dto)) //todo: uniqueness check for states or use a set
     dto.setPersons(persons);

     return dto;
  }
}

其他所有内容都将使用Reference<State>之类的数据结构,但我认为这不值得。您也可以通过除去一侧来打破循环依赖关系,并在需要时将Person与它的States相关联,或在另一层上存储Map<State, List<Person>>。但是我仍然更喜欢在文章开头概述的方法。

在旁注:也许尝试datus(免责声明:我是作者),看看它是否适合您的其他转换任务并简化您的工作:)