Reputation: 2473
I am use to designing my applications using a more database driven approach and now I would like to start from the model. I have the following requirements and would like to get your take on it. It's basically an Activity with points associated with it.
Activity with Super 30 Doctor
Activity with 120 Doctor
Activity with Partnership
Activity with Follow-Up Partnership Meeting
So, I'm trying to decided if I use an inheritance hiearchy here for each activity type or an enumeration off of the activity. So, is each activity responsible for calculating their points (but in some instances then need to know the total activity count to decide) or do I have some scorer component know all the logic.
Any ideas would be great!
I have this design thus far, but I do not know where to handle the Super 30 rules:
public abstract class ActivityBase {
public int Id { get; set; }
public DateTime Date { get; set; }
public abstract double CalculatePoints();
}
public class SuperThirtyActivity : ActivityBase {
public bool WithCE { get; set; }
public bool WithLocalAdvocate { get; set; }
public override double CalculatePoints() {
if (Date.Month == 3 && Date.AddDays(7).Month == 4)
return 1;
else if (WithCE || WithLocalAdvocate)
return 2;
else
return 1;
}
}
public class OneTwentyActivity : ActivityBase {
public override double CalculatePoints() {
return .5;
}
}
public class PartnershipActivity : ActivityBase {
public override double CalculatePoints() {
return 2;
}
}
Now to handle the Super 30 rules, I thought of introducing the following class. However, some of the domain logic is leaking in here. Is this ok or any other ideas??
public class Scorer {
public double CalculateScore(IEnumerable<ActivityBase> activities) {
var score = activities.Select(a => a.CalculatePoints()).Sum();
var count = activities.Count(a => a is SuperThirtyActivity);
if (count < 4)
score--;
else if (count > 6)
score += count;
return score;
}
}
Upvotes: 1
Views: 119
Reputation: 59453
Since some of the points are based on aggregated activities, it looks like there is another concept that is not being captured in the object model, ActivityCollection. It is hinted at in the parameter to Scorer.CalculateScore, but perhaps it needs to be made explicit. The ActivityCollection could then calculate the scores since it is holding all of the information necessary.
On the other hand, the Scorer object can probably serve that role just as well. It is OK that the domain logic is in the Scorer object, since it is only the logic necessary for Scorer to do exactly what its name implies. If you keep Scorer, but move the point values from the activity classes into it, then that structure may serve just as well, if not better.
Upvotes: 0
Reputation: 3151
If the activity base class will contain no logic, I recommend making an IActivity interface and make 4 classes to implement it instead of inheritance. IActivity should have a method like CalculatePoints to be implemented by every realizing class.
If you are not going to check for Activity types anywhere in your application I mean if you will never have code like :
if (activity is PartnershipActivity){
//do something
}
else if (activity is FollowUpActivity) {
// do something else
}
and if you are sure there will be no new activity types introduced into the application in the future you may then consider making one Activity class with enum field as you said and do all the checks and calculations you mentioned in its business logic.
Upvotes: 1