One approach is to make the rules inner classes of Employee
. The benefit of this approach is that the fields can remain private. Also, the invocation of the rules can be enforced by the Employee class itself, ensuring that they are always invoked when needed:
class Employee
{
string id;
string name;
float salary;
float pensionPot;
bool pension;
bool eligibleForPension;
public void ChangeSalary(float salary)
{
this.salary = salary;
ApplyRules();
}
public void MakeEligibleForPension()
{
this.eligibleForPension = true;
ApplyRules(); // may or may not be needed
}
void ApplyRules()
{
rules.ForEach(rule => rule.Apply(this));
}
readonly static List<IEmployeeRule> rules;
static Employee()
{
rules = new List<IEmployeeRule>
{
new SalaryBasedPensionEligibilityRule()
};
}
interface IEmployeeRule
{
void Apply(Employee employee);
}
class SalaryBasedPensionEligibilityRule : IEmployeeRule
{
public void Apply(Employee employee)
{
if (employee.salary > 100000 && !employee.eligibleForPension)
{
employee.MakeEligibleForPension();
}
}
}
}
One problem here is that the Employee class has to contain all rule implementations. This isn't a major problem since the rules embody business logic associated with employee pensions and so they do belong together.