Как избежать дублирования DTO без наследования? - PullRequest
2 голосов
/ 29 мая 2020

Я подключаюсь ко многим социальным сетям для входа в свое приложение. У меня есть один DTO для каждого ответа социальной сети.

public class GoogleUserInfo {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
    private AgeRange ageRange;
    // more specific fields
}

public class FacebookUserInfo {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
    private String picture;
    // more specific fields
}

public class AppleUserInfo {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
    private Boolean emailVerified;
    // more specific fields
}

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

public class SocialNetworkInfo {
    protected String id;
    protected String firstName;
    protected String lastName;
    protected String email;
}

DTO социальных сетей могут расширить это, чтобы получить общие поля. Затем я мог бы использовать этот общий c DTO для реализации абстрактного коннектора, который имеет дело со всеми повторяющимися логами c между коннекторами (запрос на выполнение, анализ ответа и т.д. c ...):

abstract class AbstractConnector {
    abstract SocialNetworkInfo fetchUserInfo(String networkId);
    ...
}

Но я понял, что выше, на моем уровне обслуживания, мне понадобятся эти c поля для внесения некоторых изменений и операций.

SocialNetworkInfo networkUserInfo = facebookConnector.fetchUserInfo(facebookId);
facebookService.updatePicture(networkUserInfo.getPicture()); // can't access this specific field

Как вы думаете, что это лучший способ go через эту ситуацию без преобразования и избежания logi c или дублирования DTO?

Хотелось бы услышать ваши мысли.

Спасибо!

Ответы [ 2 ]

2 голосов
/ 29 мая 2020

В соответствии с вашей ситуацией, все модели социальных сетей имеют одинаковую природу, поэтому нормально, если вы переместите общие атрибуты в общий класс, например CommonSocialInfo. Затем я бы порекомендовал предоставить интерфейс для соединителей, например:

interface SocialNetworkConnector<T extends SocialNetworkInfo> {
    T fetchUserInfo(String userId);
}

Конечно, для общей функциональности (для соединителей) отличная идея - определить общий абстрактный класс, который реализует интерфейс выше (реализовать шаблон шаблона). Я вижу, что вы используете FacebookService и связанный с ним соединитель отдельно. Я думаю, что в этом случае неплохо использовать композицию и сделать SocialNetworkService зависимым от этого коннектора. Короче говоря, FacebookService зависит от FacebookConnecter и так далее. Просто быстрый пример:

public class FacebookService implements SocialNetworkService {
    private final SocialNetworkConnector<FacebookSocialInfo> connector;
    ...
}  

И если вам нужно реализовать несколько социальных услуг, вы можете использовать шаблон Factory для создания требуемой услуги, быстрый пример:

interface SocialNetworkServiceFactory {
    SocialNetworkService getFacebookService();
    ...
}

Если вам нужно больше подробная помощь или у вас проблемы с пониманием идеи - спрашивайте!

1 голос
/ 29 мая 2020

Если вы не хотите использовать наследование , я предлагаю рассмотреть состав . Код может выглядеть так:

public class SocialNetworkInfo {
    private String id;
    private String firstName;
    private String lastName;
    private String email;
}

public class GoogleUserInfo {
    private SocialNetworkInfo socialNetworkInfo;
    private AgeRange ageRange;
    // more specific fields
}

public class FacebookUserInfo {
    private SocialNetworkInfo socialNetworkInfo;
    private String picture;
    // more specific fields
}

public class AppleUserInfo {
    private SocialNetworkInfo socialNetworkInfo;
    private Boolean emailVerified;
    // more specific fields
}
...