I am working on an application, a module of which does the following financial operations sequentially:
When a user requests for a certain amount to be transferred into her bank account:
- check whether any transaction can happen now? (transaction can be carried out only during a certain time period)
- check whether the user has requested for a minimum amount to be withdrawn
- check whether the user has any default account
The result of all the above actions should be logged.
If all the above condition satisfies, the transaction is carried out. In future, there might be some additional checks.
Which object oriented design pattern should be best suitable for the above case?
8
It sounds like what you are looking for is a Chain of Responsibility. In this case you could have the following classes:
TransactionValidatorBase
abstract base classTransactionTimeValidator
TransactionAmountValidator
TransactionAccountValidator
That are chained together to apply however many rules you specify.
Furter Reading
- CoR on OODesign.com
- Following the CoR on JavaWorld
2
If your sequence of steps are doing mostly validation duties (as it looks you are), without mutating the inputs, I’d think indeed of the “Chain of Responsibility” pattern, as explained in his answer by @p.s.w.g
But since your question is a bit more generic, I’d like to add the “Pipeline processing” as well, since with this one, a step would produce an output that would become the input for the next step (thus mutating original input).
Here are two articles about it:
Pipeline collection by Martin Fowler
More theoretical discussion about the pattern
The correct pattern here is really depends on a context.
Before picking any particular pattern to stick to, I will try to find out answers to those questions:
- Is it required to create different combinations of (1,2,3) checks at run-time ?
- Do they need the same variables to perform their actions or they are greatly different?
- How precise the error messages should be?
- In case of failure do user retry from (1)st step always?
- How concurrency is handled?
- Does each method adds something to the request or simply validates? (say Default acct id?)
Based on a gut feeling I would code them as a plain methods with aggregating parameter for error codes.
public void DoTransaction(IErrorAgregator error, TransactionRequest request)
{
if(!IsTransactionInCertainTimePeriod(request, error)) return;
if(!IsTransactionAmountInUserBounds(request, error)) return;
if(!UserHaveDefaultAccount(request, error)) return;
bankingTransactor.PerformTransaction(request);
}
It might be a good idea to put DoTransaction in the “ITransactionValidationStragegy” interface and create a layer super-type which will contain validation boilerplate code.
However, in this design I am assuming that validation logic is determined at compile time.
While the patterns are already mentioned here, i would suggest you to think about how you would like to use the same in your application, based on the frameworks you are using.
For instance, the validation you would like to do, most likely will keep changing as and when time progress (may be you want to add a new validation in future which restricts transactions to 10 a day). Also, you may not want to do the validation before your actual business service or integration code kicks in.
It would be good, if you can have the validations added as configurable ones.
In case you are using Struts, using interceptors might be a good idea. In case of spring, beans injection as dependency gives you more flexibility.
My suggestion is not only to look at the patterns/idioms but also look at the framework which you use to build the application and see how best you can fit in your requirement from a futuristic point of view.
According to my understanding whatever is required can be fitted into the command pattern like below. Class design can be done as per below.
interface Transaction{
void performAction();
}
class Banking{
void moneyValidation(){
//Validate Here
}
void timeValidation(){
//validate Here
}
}
class TimeValidation implements Transaction{
public Banking bank;
public TimeValidation (Banking bnk){
bank=bnk;
}
void performAction(){
bnk.timeValidation();
}
class MoneyValidation Implements Transaction{
public Banking bank;
public MoneyValidation(Banking bnk;){
bank=bnk;
}
void performAction(){
bnk.moneyValidation();
}
}
class Control{
private List val_list=new ArrayList();
void storeValidation(Transaction trans){
val_list.add(trans);
trans.performAction(val_list.getFirstAndRemove());
}
}
//Same for other validation classes
Your Client class will contain the following code snippet:
Banking bnk = new Banking();
MoneyValidation m_val = new MoneyValidation (bnk);
TimeValidation t_val = new TimeValidation (bnk);
Control ctrl = new Control();
ctrl.storeValidation(m_val);
ctrl.storeValidation(t_val);
This is as per my understanding, with the scenario which has been given above.
1