如何在没有继承的情况下避免 DTO 重复?

How can I avoid DTOs duplication without inheritance?

我正在连接许多社交网络以在我的应用程序中登录。 每个社交网络响应都有一个 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
}

在每个社交网络连接器中,我都采用类似的步骤来获取信息,因此我认为我可以使用一些 DTO,如下所示:

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

社交网络 DTO 可以扩展它以获得公共字段。然后我可以使用这个通用 DTO 来实现一个抽象连接器,它处理连接器之间的所有重复逻辑(发出请求、解析响应等...):

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

但我意识到,在上面,在我的服务层中,我需要那些特定的字段来进行一些更改和操作。

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

您认为在不强制转换和避免逻辑或 DTO 重复的情况下解决这种情况的最佳方法是什么?

很想听听你的想法。

谢谢!

根据您的情况,所有社交网络模型都具有相同的性质,因此如果您将共同属性移动到共享 class 就可以了,例如 CommonSocialInfo。然后我建议为连接器提供接口,如:

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

当然,对于通用功能(对于连接器)来说,定义实现上述接口(实现模板模式)的通用抽象 class 是个好主意。我看到您正在分别使用 FacebookService 和相关连接器。我认为在这种情况下使用组合并使 SocialNetworkService 依赖于它的连接器是个好主意。简而言之,FacebookService 依赖于 FacebookConnecter 等。举个简单的例子:

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

如果你需要实现多个社会服务,你可以使用工厂模式来生产所需的服务,快速示例:

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

如果您需要更详细的帮助或者您在理解这个想法方面有困难 - 请随时提出!

如果你不想使用继承,我建议考虑组合。代码如下所示:

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
}