Need help with the domain model

advertisements

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

  1. Minimum 4 per month
  2. Subtract a point if you do not hit the minimum (4)
  3. 1 Point or 2 Points if you go over 6 per month
  4. 2 Points when with a local advocate

Activity with 120 Doctor

  1. .5 Points

Activity with Partnership

  1. 2 Points

Activity with Follow-Up Partnership Meeting

  1. 2 Points

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;
    }
}


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.