Simple Fluent Interface for Design By Contract

Design by Contract is very important in programming. It make us avoid many errors while we code. I believe we was one time to do this one

public string ProcessingInvoiceForAllCustomers()
{
    Contract.Assert(CustomerRepository != null, "CustomerRepository is not null");
    Contract.Assert(CustomerService != null, "CustomerService is not null");
    Contract.Assert(TaxStrategy != null, "TaxStrategy is not null");

    var customers = CustomerRepository.GetAll();
    foreach (var customer in customers)
    {
         CustomerService.CalculateTax(customer, TaxStrategy);
     }

     return BuildReport(customers);
 }

As you see, we must to check three fields: CustomerRepository, CustomerService and TaxStrategy is not null. And if you have other method, you also check it again. But you can write one common method for check it as:

public void EnsureAllInjectObjectIsNotNull()
{
    Contract.Assert(CustomerRepository != null, "CustomerRepository is not null");
    Contract.Assert(CustomerService != null, "CustomerService is not null");
    Contract.Assert(TaxStrategy != null, "TaxStrategy is not null");
}

And call this method in each method that you want to use three fields: CustomerRepository, CustomerService and TaxStrategy as

public string ProcessingInvoiceForAllCustomers()
{
    EnsureAllInjectObjectIsNotNull();

    var customers = CustomerRepository.GetAll();
    foreach (var customer in customers)
    {
        CustomerService.CalculateTax(customer, TaxStrategy);
    }

    return BuildReport(customers);
}

I don't like this way, but I do that in many years. And I also thought about that a long time ago. And now I suggest one way is very clear and lightweight for do that as

public string ProcessingInvoiceForAllCustomers()
{
    DBC.ValidateContractForClass(this);

    var customers = CustomerRepository.GetAll();
    foreach (var customer in customers)
    {
        CustomerService.CalculateTax(customer, TaxStrategy);
    }

    return BuildReport(customers);
}

DBC is a instance that I inject it into the class as:

public ICustomerRepository CustomerRepository { get; private set; }

public ICustomerService CustomerService { get; private set; }

public ITaxStrategy TaxStrategy { get; private set; }

public IFluentDBCConfiguration DBC { get; private set; }        

public ShoppingApplication(
    ICustomerRepository customerRepository,
    ICustomerService customerService,
    ITaxStrategy taxStrategy,
    IFluentDBCConfiguration dbc)
{
    CustomerRepository = customerRepository;
    CustomerService = customerService;
    TaxStrategy = taxStrategy;
    DBC = dbc;
}

And I can configure IFluentDBCConfiguration outside this class as

Container.RegisterInstance(typeof(ICustomerRepository), typeof(StubCustomerRepository));
Container.RegisterInstance(typeof(ICustomerService), typeof(CustomerService));
Container.RegisterInstance(typeof(ITaxStrategy), typeof(DefaultTaxStrategy));

var obj = FluentDBCConfiguration.GetInstance()
                  .WithClass<ShoppingApplication>()
                      .Field(x => x.CustomerRepository)
                          .PreCondition()
                          .IsNotNull("CustomerRepository is null!")
                      .Field(x => x.CustomerService)
                          .PreCondition()
                          .IsNotNull("CustomerService is null!")
                      .Field(x => x.TaxStrategy)
                           .PreCondition()
                           .IsNotNull("TaxStrategy is null!")
                  .Completed();

Container.RegisterInstance(typeof(IFluentDBCConfiguration), obj);

Now I really love this way. That is for fun, I also try to make to code clean and can be easy to read. 

FluentDBC was built on Microsoft's Code Contract. It call Code Contract for validation the contract inside it. It have a own domain entity for identify the class and type that it want to validation. It is so lightweight in this time, less than 20KB. It look like tiny than any components with same function. I just keep in mind that I will make it is as simple as possible.

Last edited May 13, 2011 at 6:39 PM by thangchung, version 3