Object Oriented Way of Writing Business Rules
Decouple business rules in an Object Oriented way
Introduction
We can't ignore the fact that as business grows in competitive marketing environment, the way of doing business also changes which means there will be more business rules added in future. It means our application should be flexible enough to cater to those changes.
In this article, we will discuss how to write business rules in an Object Oriented way which are independent from the client code logic.
Background
Let's take an example of driving license rules. A person needs to check whether s/he is eligible for full driving license or not.
When a person will apply for a driving license, we have to validate the following business rules:
- Age must be greater or equal to 18
- Must have learners license for at least three months which should not be expired (means should not be older than 12 months)
Tools
- Visual Studio Professional 2015
- Console application to consume business rules as client application
Using the Code
Create a console application in Visual Studio 2015. I have given the name DrivingLicenseApp
.
Add object model to hold license details and another object to hold the result.
LicenseDetails
This object will contain the following properties:
Age
LearnerLicenseDuration
public class LicenseDetails
{
public int Age { get; set; }
public int LearnerLicenseDuration { get; set; }
}
Also add OperationResult
object to hold the validation result.
public class OperationResult
{
public IEnumerable<string> Messages { get; set; }
public bool IsSuccessful { get { return !Messages.Any(); } }
}
I'm adding these objects under Models folder in DrivingLicenseApp
project.
Validation Rules
We have defined model and result objects. Now we need to write validation rules. I'm creating Rules folder under DrivingLicenseApp
project to keep all rules together. There can be multiple rules for validation and there is a chance for new rules in future as well.
I'm using interface which will be implemented by every rule. This interface will have only one method and return error string if the validation is failed.
public interface IRule
{
string Validate();
}
Age Rule
Create a class AgeRule
which will implement IRule.Validate
method. This method will return error message if the given age is equal to or less than 18
.
public class AgeRule : IRule
{
private readonly int _age;
public AgeRule(int age)
{
_age = age;
}
public string Validate()
{
var errorMessage = string.Empty;
if (_age < 18)
{
errorMessage = "Age must be greater than 18 years";
}
return errorMessage;
}
}
We've defined our first rule here. Now we need to define another rule which will validate duration of learner license and it should not be expired.
LearnerLicense Rule
Similar to age rule, create an object for LearnerLicense
rule validation. As per the rules, candidate learner license should be less than 3 months and greater than 12 months.
public class LearnerLicenseRule : IRule
{
private readonly int _learnerLicenseDuration;
public LearnerLicenseRule(int learnerLicenseDurationInMonths)
{
_learnerLicenseDuration = learnerLicenseDurationInMonths;
}
public string Validate()
{
var errorMessage = string.Empty;
if (_learnerLicenseDuration < 3)
{
errorMessage = "Learner License should be at least 3 months";
}
else if (_learnerLicenseDuration > 12)
{
errorMessage = "Learner License has expired after 12 months";
}
return errorMessage;
}
}
Here the noticeable thing is that we are passing data in constructor parameter which needs to be validated. The reason is to use common interface for all the rules implementation.
Rules Execution
I'm using console application, you can use as per your requirement to execute the rules. I've created one method to validate all the business rules and call its validate
method. The result of validation will be stored in OperationResult
and all the error messages will be in Messages
collection (if any).
private static OperationResult ValidateLicenseDetails(int age, int learnerLicenseDuration)
{
var rules = new List<IRule>
{
new AgeRule(age),
new LearnerLicenseRule(learnerLicenseDuration)
};
var result = new OperationResult();
var errorMessages = new List<string>();
rules.ForEach(rule =>
{
var error = rule.Validate();
if (!string.IsNullOrWhiteSpace(error))
errorMessages.Add(error);
});
return new OperationResult
{
Messages = errorMessages
};
}
Points of Interest
Whenever a new rule is added in future, you just need to write an object and add to the rules collection. Your validation logic is completely decoupled from your client code. I hope this will help you in writing business rules in an object oriented way.