I have tried to ask a variant of this question before. I got some helpful answers, but still nothing that felt quite right to me. It seems to me this shouldn\'t really be that h
You don't need the Factory if your subclasses filter themselves on what they want to charge for. That requires a Project class to hold the data, if nothing else:
class Project {
TaskType Type { get; set; }
int? NumberOfHours { get; set; }
}
Since you want to add new calculations easily, you need an interface:
IProjectHours {
public void SetHours(IEnumerable projects);
}
And, some classes to implement the interface:
class AnalysisProjectHours : IProjectHours {
public void SetHours(IEnumerable projects) {
projects.Where(p => p.Type == TaskType.Analysis)
.Each(p => p.NumberOfHours += 30);
}
}
// Non-LINQ equivalent
class AnalysisProjectHours : IProjectHours {
public void SetHours(IEnumerable projects) {
foreach (Project p in projects) {
if (p.Type == TaskType.Analysis) {
p.NumberOfHours += 30;
}
}
}
}
class WritingProjectHours : IProjectHours {
public void SetHours(IEnumerable projects) {
projects.Where(p => p.Type == TaskType.Writing)
.Skip(0).Take(2).Each(p => p.NumberOfHours += 30);
projects.Where(p => p.Type == TaskType.Writing)
.Skip(2).Take(6).Each(p => p.NumberOfHours += 20);
projects.Where(p => p.Type == TaskType.Writing)
.Skip(8).Each(p => p.NumberOfHours += 10);
}
}
// Non-LINQ equivalent
class WritingProjectHours : IProjectHours {
public void SetHours(IEnumerable projects) {
int writingProjectsCount = 0;
foreach (Project p in projects) {
if (p.Type != TaskType.Writing) {
continue;
}
writingProjectsCount++;
switch (writingProjectsCount) {
case 1: case 2:
p.NumberOfHours += 30;
break;
case 3: case 4: case 5: case 6: case 7: case 8:
p.NumberOfHours += 20;
break;
default:
p.NumberOfHours += 10;
break;
}
}
}
}
class NewProjectHours : IProjectHours {
public void SetHours(IEnumerable projects) {
projects.Where(p => p.Id == null).Each(p => p.NumberOfHours += 5);
}
}
// Non-LINQ equivalent
class NewProjectHours : IProjectHours {
public void SetHours(IEnumerable projects) {
foreach (Project p in projects) {
if (p.Id == null) {
// Add 5 additional hours to each new project
p.NumberOfHours += 5;
}
}
}
}
The calling code can either dynamically load IProjectHours
implementors (or static them) and then just walk the list of Project
s through them:
foreach (var h in AssemblyHelper.GetImplementors()) {
h.SetHours(projects);
}
Console.WriteLine(projects.Sum(p => p.NumberOfHours));
// Non-LINQ equivalent
int totalNumberHours = 0;
foreach (Project p in projects) {
totalNumberOfHours += p.NumberOfHours;
}
Console.WriteLine(totalNumberOfHours);