Marco
Marco

Reputation: 2473

Need some help with domain model

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

Upvotes: 1

Views: 119

Answers (2)

Jeffrey L Whitledge
Jeffrey L Whitledge

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

M.Sameer
M.Sameer

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

Related Questions