Рубрики
Без рубрики

откажитесь от своих фабрик – преобразование данных с помощью datus

(отказ от ответственности: я являюсь автором datus) Вы снова работаете с Java, возможно, вы разрабатываете n… Помеченный как java, функциональный, с открытым исходным кодом.

(отказ от ответственности: я являюсь автором datus )

Вы снова работаете с Java, возможно, вы разрабатываете новую (микро) сервис-ориентированную архитектуру и в настоящее время интегрируете другой сервис, Персональная служба , в вашу AService . Вы получаете Личный ресурс и, как вы уже поняли, вы берете этот объект и преобразуете его в свой собственный объект Person , чтобы не полагаться на структуры данных, которыми вы не владеете в своей бизнес-логике:

//external object
class PersonResource {
    //getters + setters omitted for brevity
    private String firstName;
    private String lastName;
}
//internal object
class Person {
    //getters + setters omitted for brevity
    private String firstName;
    private String lastName;
}

Давайте создадим этот удобный объект factory/converter:

public PersonFactory {
    public Person create(PersonResource resource) {
      Person person = new Person();
      person.setFirstName(resource.getFirstName());
      person.setLastName(resource.setLastName());
      return person;
    }
}

Это работает, но как насчет других 5-10 сервисов и их 15-30 объектов данных? Вся эта шаблонность довольно раздражает, не так ли? И только сейчас вы осознаете, что Ресурс Person может быть нулевым итак, ваш инструмент покрытия тестов жалуется на то, что вы не написали тест для такого тривиального класса.

Что, если бы существовал способ объявить, как выполняется преобразование, определить, как оно выполняется, но не реализовать его? Введите даты :

Mapper mapper = Datus.forTypes(PersonResource.class, Person.class)
    .mutable(Person::new)
    .from(PersonResource::getFirstName).into(Person::setFirstName)
    .from(PersonResource::getLastName).into(Person::setLastName)
    .build();

Довольно лаконичный и понятный – декларативный подход пока выглядит нормально. Но как насчет той нулевой проверки, о которой я говорил? Давайте осуществим это, но как?

Mapper mapper = Datus.forTypes(PersonResource.class, Person.class)
    .mutable(Person::new)
    .from(PersonResource::getFirstName).into(Person::setFirstName)
    .from(PersonResource::getLastName).into(Person::setLastName)
    .build();

Mapper> notNullMapper = 
    mapper.predicateInput(Objects::nonNull)

Что ж, это было легко, но проект развивается: фамилия может быть нулевой и должна быть прописной в вашем сервисе. Вы не подвергаете сомнению это странное требование и добавляете новую функциональность:

Mapper mapper = Datus.forTypes(PersonResource.class, Person.class)
    .mutable(Person::new)
    .from(PersonResource::getFirstName).into(Person::setFirstName)
    .from(PersonResource::getLastName)
         .given(Objects::nonNull, ln -> ln.toUpperCase()).orElseNull()
         .into(Person::setLastName)
    .build();

Mapper> notNullMapper = 
    mapper.predicateInput(Objects::nonNull)

Фантазия! Но вам не нужны никакие Person объекты без фамилия должна быть действительной, поэтому давайте добавим предикат для выходного объекта (конечно, вы уже могли бы сделать это для входного объекта, но позвольте мне показать еще несколько функций 😉 ):

Mapper mapper = Datus.forTypes(PersonResource.class, Person.class)
    .mutable(Person::new)
    .from(PersonResource::getFirstName).into(Person::setFirstName)
    .from(PersonResource::getLastName)
         .given(Objects::nonNull, ln -> ln.toUpperCase()).orElseNull()
         .into(Person::setLastName)
    .build();

Mapper> predicatedMapper = 
    mapper.predicate(Objects::nonNull, p -> p.getLastName() != null)

Так что же мы получили?

  • объявляйте свои сопоставления, не реализуйте их
  • нет необходимости в модульных тестах для таких тривиальных проверок на обнуляемость: они объявляются и, как только возникает необходимость в них, просто добавляются (это спорный момент)
  • больше никаких фабричных классов всего один интерфейс
  • datus работает даже для неизменяемых объектов назначения (ознакомьтесь с примерами readme)
  • отражение не используется, все статически типизировано проверен

О, и я уже упоминал об этом Mapper также предоставляет Преобразование списка (ввод списка) и Map convertToMap(ввод списка) из коробки? Узнайте больше в readme или в расширенном руководстве пользователя , чтение которого занимает всего около 15 минут!

Вам нравится более неявный/автоматический/управляемый аннотациями процесс преобразования? Ознакомьтесь с альтернативами данным, такими как MapStruct или ModelMapper .

Спасибо, что уделили мне время, свяжитесь со мной, если у вас возникнут какие-либо вопросы:)

Оригинал: “https://dev.to/roookeee/abandon-your-factories-data-conversion-with-datus-42kn”