Billing for work using an hourly, dual, or flat rate I asked this on Stack Overflow and got some good ideas, but was advised to post here instead. There are obviously several ways to code this, each with a drawback and a benefit.

A person works a number of hours and can bill for the work in one of three ways:


Hourly: the number of hours worked * hourly rate
Dual: (for simplicity sake) first rate + second rate
Flat: just an amount, regardless of the hours worked


Here's the code that I came up with, but I just can't help but think that there's a much more elegant way to do this. In the code below I have a class per rate type, one base class for a rate, a person, and a calculator that does the math. Suggestions?

using System;

public class Program
{
    public static void Main()
    {
        Person p = new Person();
        p.HoursWorked = 2;
        p.Rate = new Hourly(10);
        //p.Rate = new Dual(10, 1);
        //p.Rate = new Flat(10);
        Console.WriteLine(Calculator.Calculate(p));
    }
}



public class Person
{
    public RateStyle Rate { get; set; }
    public int HoursWorked { get; set; }
}

public abstract class RateStyle 
{
}

public class Dual : RateStyle
{
    public int First { get; private set; }
    public int Second { get; private set; }

    public Dual(int a, int b)
    {
        First = a;
        Second = b;
    }
}

public class Hourly : RateStyle
{
    public int Rate { get; private set; }
    public Hourly(int r)
    {
        Rate = r;
    }
}

public class Flat : RateStyle
{
    public int Rate { get; private set; }
    public Flat(int r)
    {
        Rate = r;
    }
}

public static class Calculator
{
    public static int Calculate(Person p)
    {
        if (p.Rate is Hourly)
        {
            return p.HoursWorked * ((Hourly)p.Rate).Rate;
        }
        if (p.Rate is Dual)
        {
            return ((Dual)p.Rate).First + ((Dual)p.Rate).Second;
        }

        return ((Flat)p.Rate).Rate;
    }
}
OO or not

The first thing to do is decide whether or not you want an object-oriented design for this problem. From the requirements you've described, there's a very simple solution that doesn't need any real design work at all:

public static int CalculateFee(int flatRate, int hourlyRate, int hours)
{
    return flatRate + hourlyRate*hours;
}


(The two parts of a "dual rate" would just be summed before being passed in, and either flatRate or hourlyRate could be 0)

You can then carry around those variables however is most convenient for you. For example maybe you'd put the rates together into some property-bag class:

public class Rate
{
    public int Hourly { get; set; }
    public int Flat { get; set; }
}


Or maybe you'd just pass them around as integers. Likewise whether CalculateFee was a public method somewhere or a private method, or even in-lined in another method, is really just a choice about how to organize things to read most clearly, rather than about design.



I think the above should be your default starting point. Building a design means making decisions, and every decision is a potential wrong decision, which becomes technical debt. So you should never build more or earlier than you're driven to by your requirements.

But there are some reasons you may immediately want a heavier design than this. For example:


You know- or think it's very likely- that you'll have to add new types of rates in addition to flat, dual and hourly.
There may be more functionality that you need associated with each rate, like wanting to be able to write a descriptive string ("A rate of 30$ per hour").
You want to be able to replace a rate with a test double for unit testing (I'm not sure that's really appropriate with these classes, it's hard to know without seeing how they're used)


Polymorphism

I won't write out a full OO version because Dmitry Nogin's answer already demonstrates this really well. 

But to distill out the key point from that, if you're going to use an OO solution, you want to use polymorphism. If you're doing code like:

IThing thing;

if(thing is ThingTypeA)
{
    CalculationA(thing);
}
else if(thing is ThingTypeB)
{
    CalculationB(thing);
}
else if...


Then that's a pretty good sign that you should instead have a Calculation method on IThing, with a different implementation for ThingTypeA and ThingTypeB. That's a core part of OO design, and one that's easy to apply here (as Dmitry's answer shows)

Note that this also lets you encapsulate your data- those integer fields can be private to the Rate implementations. Your classes aren't just bags to hold data for anyone to read, they provide useful behaviour.