Reputation: 1437
I need your help about a design I made that I'm not happy with. The application is consuming RSS news (The articles's RSS, and the comments's RSS of each article).
I made an interface called IDataService which provide the basic behavior of the data provider.
public interface IDataService
{
Task<List<Item>> GetItemsAsync(string url, IItemsParser parser);
Task<List<Comment>> GetItemCommentsAsync(string url, ICommentsParser parser);
}
As you see, each function get as parameters the web-service url (the RSS feed url, in my case) and an interface of some parser that knows how to deal with the data.
These are the interfaces of the two parses:
public interface IItemsParser
{
List<Item> ParseRawData(string rawData);
}
public interface ICommentsParser
{
List<Comment> ParseRawData(string rawData);
}
Now let's be concrete for a bit, this is the implementation class:
public class MyRSSDataService : IDataService
{
public async Task<List<Item>> GetItemsAsync(string url, IItemsParser parser)
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(new Uri(url));
if (response.IsSuccessStatusCode)
{
var jsonResponse = await response.Content.ReadAsStringAsync();
List<Item> items = parser.ParseRawData(jsonResponse);
return items;
}
else
{
throw new NetworkConnectionException(response.StatusCode.ToString());
}
}
}
public async Task<List<Comment>> GetItemCommentsAsync(string url, ICommentsParser parser)
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync(new Uri(url));
if (response.IsSuccessStatusCode)
{
var jsonResponse = await response.Content.ReadAsStringAsync();
List<Comment> comments = parser.ParseRawData(jsonResponse);
return comments;
}
else
{
throw new NetworkConnectionException(response.StatusCode.ToString());
}
}
}
}
I feel like I really violate the DRY principle, and I'm not feeling great with the interfaces I made that looks so similar.
Upvotes: 3
Views: 115
Reputation: 38077
Use generics:
public interface IDataService
{
Task<List<T>> GetDataAsync<T>(string url, IParser<T> parser);
}
public interface IParser<T>
{
List<T> ParseRawData(string rawData);
}
Then your implementation looks like this:
public class DataService : IDataService
{
public async Task<List<T>> GetDataAsync<T>(string url, IParser<T> parser)
{
// Do work
return parser.ParseRawData("blah");
}
}
public class ItemParser : IParser<Item>
{
public List<Item> ParseRawData(string rawData)
{
// Do work
}
}
public class CommentParser : IParser<Comment>
{
public List<Comment> ParseRawData(string rawData)
{
// Do work
}
}
Now when you use it, it is as simple as:
var x = new DataService();
var y = new ItemParser();
await x.GetDataAsync("", y);
var z = new CommentParser();
await x.GetDataAsync("", z);
Upvotes: 6