Reputation: 196669
i have this code below that loops through a data structure builds up a dictionary.
I have this code duplicated multiple times with the only difference being the Key to the dictionary
so in the below code it happens to be:
task.Project + task.Name
that is the key to the dictionary but in other cases its just:
task.Project
or just
task.Name
here is an example of one of hte hard coded "Bucket" methods.
My goal is to have a generic "Bucket" method where i can have a callback or some way to pass in the function for calculating the key.
What is the best way of doing this ??
private Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings)
{
Dictionary<string, TeamHours> dict = new Dictionary<string, TeamHours>();
foreach (var name in timebookings.Keys)
{
TimeBooking tb = timebookings[name];
Person p = tb.Person;
foreach (var booking in tb.WeeklyTimeBookings.Keys)
{
var item = tb.WeeklyTimeBookings[booking];
foreach (var task in item.TaskSlices)
{
if (dict.ContainsKey(task.Project + task.Name))
{
TeamHours th = dict[task.Project + task.Name];
th.Hours = th.Hours + task.Hours;
}
else
{
TeamHours th = new TeamHours();
th.Hours = task.Hours;
th.Project = task.Project;
th.Task = task.Name;
th.Workstream = tb.Person.OrganisationalUnitName;
dict[task.Project + task.Name] = th;
}
}
}
}
return dict;
}
Upvotes: 2
Views: 541
Reputation: 27974
Well, you mostly answered the question yourself. Either pass a delegate into the method or inherit different implementations and specialize by implementing an abstract method. Another option is separating the key-building algorithm as an interface, which leads to best separation of concerns, but the overhead might be too much for simple scenarios.
private Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings, Func<string, Task> getTaskKey)
{
…
dict[getTaskKey(task)] = th;
…
}
Good for use in highly-localized scenarios (i.e. implementation and usages private to a single class) with just a few simple key-building expressions.
class abstract BucketAlgorithm
{
protected abstract string GetTaskKey(Task task);
public Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings)
{
…
dict[GetTaskKey(task)] = th;
…
}
}
class SpecificBucketAlgorithm : BucketAlgorithm
{
protected override string GetTaskKey(Task task) { … }
}
Good for use within a medium scope like just one assembly, where there's no need for better separation of concerns (interfaces from implementation), or where are several non-trivial key-building algorithms required.
interface ITaskKeyGenerator
{
string GetTaskKey(Task task);
}
class BucketAlgorithm
{
public BucketAlgorithm(ITaskKeyGenerator taskKeyGenerator)
{
this.taskKeyGenerator = taskKeyGenerator;
}
private ITaskKeyGenerator taskKeyGenerator;
public Dictionary<string, TeamHours> BucketByProjectTask(Dictionary<string, TimeBooking> timebookings)
{
…
dict[taskKeyGenerator.GetTaskKey(task)] = th;
…
}
}
Good for scenarios where thorough separation of concerns is required or where multiple complex key-building algorithms might exist, or even be provided from the “outside” by users of an API.
Upvotes: 2