Search code examples
c#design-patternsstrategy-patterncode-structure

c# Strategy Pattern per user


I have a very simple scenario. My site's user can be either a monthly membership or an annual membership

public class User
{
    public string UserName { get; set; }
    public MembershipType MembershipType { get; set; }
}

public enum MembershipType
{
    MONTHLY,
    ANNUALLY
}

and then depending on the membership, I apply a different billing strategy:

public interface IBillingStrategy
{
    void Bill(User user);
}

if (user.MembershipType == MembershipType.ANNUALLY)
{
     _billingStrategy = new AnnualBillingStrategy();
}
else if (user.MembershipType == MembershipType.MONTHLY)
{
      _billingStrategy = new MonthlyBillingStrategy();
}

This is very straight forward and simple. Now business comes along and says "I want to look after my friend Bob, I want you to calculate his bill slightly differently to everyone else!"

So If I continue the pattern I can make a BobBillingStrategy. then I can add some extra logic, now I have 2 ways I can identify Bob

if (user.UserName.Equals("bob"))
{
     _billingStrategy = new BobBillingStrategy();
}

This feels dirty as I am hard coding a username, and just my luck bob creates a new user. So I can add a boolean property to my user called IsBob

if (user.IsBob)
{
     _billingStrategy = new BobBillingStrategy();
}

Both just seem to smell funny to me. And I can see what is going to happen, eventually I am going to start testing for Fred, and Ted also. My code above will work, but I am certain there must be a cleaner solution.

Thanks


Solution

  • I would have Membership as a class that held default billing, etc. it would be a ton cleaner that a bunch of if's:

    public class Membership
    {
    
        public String Name { get; private set; }
        public BillingStrategy DefaultBillingStrategy {get; private set; }
        //Other properties
    
            public Membership(string name, BillingStrategy defaultBillingStrategy)
            {
    
                Name = name;
                DefaultBillingStrategy = defaultBillingStrategy;
    
            }
    
    }
    

    then, you do something like this with your User:

    public class User
    {
    
        //same as before
    
        public BillingStrategy BillingStrategy {get; set; }
    
        public User(string Name, Membership membership, BillingStrategy billingStrategy = null)
        {
    
            name = Name;
            MemberShip = memberShip;
            BillingStrategy = billingStrategy ? membership.DefaultBillingStrategy;
    
        }
    
    }
    enter code here
    

    also; since a user does not want to pay for jan thorugh jun if they join in jul, you probably want to save some information about when membership expires on the user, and let the membership set this value on/after billing