Reputation: 43
I am connecting with many social networks for login in my application. I have one DTO for each social network response.
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
}
In each social network connector, I make similar steps to fetch the information, so I thought I could go with some DTO as follows:
public class SocialNetworkInfo {
protected String id;
protected String firstName;
protected String lastName;
protected String email;
}
Social networks DTOs could extend this to obtain the common fields. Then I could use this generic DTO to implement an abstract connector that deals with all the duplicate logic between connectors (make request, parse response, etc...):
abstract class AbstractConnector {
abstract SocialNetworkInfo fetchUserInfo(String networkId);
...
}
But I realized that above, in my service layer, I would need those specific fields to make some changes and operations.
SocialNetworkInfo networkUserInfo = facebookConnector.fetchUserInfo(facebookId);
facebookService.updatePicture(networkUserInfo.getPicture()); // can't access this specific field
What do you think that's the best way to go through this situation without casting and avoiding logic or DTO duplication?
Would love to hear your thoughts.
Thanks!
Upvotes: 4
Views: 1686
Reputation: 5207
If you don't want to use inheritance, I'd suggest to consider composition. The code can look as follows:
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
}
Upvotes: 3
Reputation: 2610
According to your situation, all social network models have the same nature, so it's ok if you move common attributes to shared class like CommonSocialInfo
. Then I would recommend to provide interface for the connectors like:
interface SocialNetworkConnector<T extends SocialNetworkInfo> {
T fetchUserInfo(String userId);
}
Of course for common functionality(for connectors) is great idea to define common abstract class that implements interface above (implement Template pattern). I see that you are using FacebookService
and related connector separately. I think that good idea to use composition in this case and make SocialNetworkService dependent on it connector. In short, FacebookService depends on FacebookConnecter and so on. Just a quick example:
public class FacebookService implements SocialNetworkService {
private final SocialNetworkConnector<FacebookSocialInfo> connector;
...
}
And if you need to implement multiple social service, you can use Factory pattern to produce required service, quick example:
interface SocialNetworkServiceFactory {
SocialNetworkService getFacebookService();
...
}
If you need more detailed help or you have troubles with understanding of the idea - feel free to ask!
Upvotes: 3