Reputation: 447
I hope you guys can give me some good suggestions. I am thinking how to make a good architecture for C# development. I am trying my best to explain scenarios because im not good at english:
1) Two classes: Blue Bank and Red Bank
2) Third class : Rules Of Validations
3) Blue and Red Banks have several fields (values) such as AccountNumber, Amount, InvoicePeriod etc... Example here (xml):
Blue Bank
<AccountNumber>Maria 5987593457</AccountNumber>
<Amount>200.00</Amount>
<InvoicePeriod>1</InvoicePeriod>
Red Bank
<AccountNumber>8529458</AccountNumber>
<Amount>300.00</Amount>
<InvoicePeriod>0</InvoicePeriod>
Red/Blue Banks have some same rules of validations like Amount fields that must be numberic. But Red/Blue Banks have different rules of validations -- AccountNumber field must be alphanumberic in Blue Bank whereas AccountNumber must be numberic in Red Bank otherwise failed. InvoicePeriod field must be default 1 in Red Bank whereas it must be default 0 in Blue Bank otherwise failed.
My idea is:
I want to create each class of Red / Blue Bank for different rules of validation and then i also create a rules of validation class for the same rules that Blue/Red banks have.
My code here:
Blue Bank class:
Red Bank class:
RulesOfValidation class
How does it work with dictonary <,> with these classes? Or any better suggestion with your example codes?
Your help would be highly appreciated.
Upvotes: 4
Views: 1193
Reputation: 2317
I would go with IRule
interface with Validate()
method which could be implemented in concrete validation classes which could contain validation logic. Then you will be able to precess several custom rules in bank. Pass the list of IRule
type objects to bank class and run Validate()
on each passing bank parameters. So each bank could validate itself based on passed rules.
interface IRule
{
bool Validate(Bank someBank);
}
abstract class Bank
{
public string AccountNumber;
public string Amount;
public string InvoicePeriod;
private List<IRule> listOfRules = new List<IRule>();
public void ValidateAllRules(){
foreach (var ite in listOfRules){
ite.Validate(this);
//if validation will not pass then I don't know what you want to do ;)
}
}
public void AddRule(IRule rule)
{
listOfRules.Add(rule);
}
}
class RedBank : Bank
{
public RedBank(){
listOfRules.Add(new SimpleRule());
listOfRules.Add(new SimpleRule2());
}
}
class SimpleRule : IRule
{
public bool Validate(Bank someBank)
{
return someBank.AccountNumber.Contains("567");
}
}
class SimpleRule2 : IRule
{
public bool Validate(Bank someBank)
{
return someBank.Amount.Contains(".") && someBank.InvoicePeriod.Contains("-");
}
}
Upvotes: 3
Reputation: 1164
You should use System.ComponentModel.DataAnnotations
First Create abstract class Bank
abstract class Bank
{
#region fields
private List<string> errorMessages = new List<string>();
#endregion
#region publioc methods
public virtual void Validate()
{
ValidateRulesAtributes();
}
#endregion
#region helper methods
private void ValidateRulesAtributes()
{
var validationContext = new ValidationContext(this, null, null); //ValidationContext -> Reference System.ComponentModel.DataAnnotations
var result = new List<ValidationResult>();
Validator.TryValidateObject(this, validationContext, result, true);
result.ForEach(p => { errorMessages.Add(p.ErrorMessage); });
if (errorMessages.Any())
throw new Exception(errorMessages.Aggregate((m1, m2) => String.Concat(m1, Environment.NewLine, m2)));
}
protected void Validate(List<string> messages)
{
if (errorMessages == null)
errorMessages = new List<string>();
if (messages != null)
messages.ForEach(p => { errorMessages.Add(p); });
ValidateRulesAtributes();
}
#endregion
#region properties
//Abstract to indicate Validation atributes
public abstract string AccountNumber { get; set; }
public abstract double Amount { get; set; }
public abstract int InvoicePeriod { get; set; }
#endregion
}
Second Create Red and Blue Bank with data anotations
class BlueBank : Bank
{
//All is ok, no validate
public override string AccountNumber { get; set; }
public override double Amount { get; set; }
public override int InvoicePeriod { get; set; }
}
class RedBank : Bank
{
[Required()]
public override string AccountNumber { get; set; }
public override double Amount { get; set; }
[Range(0,0)]
public override int InvoicePeriod { get; set; }
public override void Validate()
{
List<string> errors=new List<string>();
if (AccountNumber != "Test")
errors.Add("Worng Account");
base.Validate(errors);
}
}
Use Atributes to validate ranges, required,etc.. Override Validate() to complex validations
This a simple example
class Program
{
static void Main(string[] args)
{
RedBank red = new RedBank();
red.AccountNumber = "Test";
red.Amount=0;
red.Validate(); //this No fail
red.InvoicePeriod = 3; //This Fail;
red.Validate();
red.AccountNumber = "PD";
red.Validate(); //this fal:
}
}
Upvotes: 0
Reputation: 7407
Specification Pattern is a good option for your problem. You can create a specification class for common bank rules and others specification classes for each specific need.
There is some c# libraries for this pattern:
Upvotes: 5