Skip to content

Amila17/PipeAndFiltersDesignPattern

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 

Repository files navigation

Pipe and Filters Design Pattern

This project demonstrate the use of Pipe and Filters Design pattern. This pattern was something that was discussed as a solution to one of the problems that arose during an implementation discussion at work. As a result I decided to implement a possible solution that fits our scenario to demonstrate how the design pattern works.

More information on the design pattern could be found at the following links:

Implementation Explaination

###Domain model:###

Withdrawal class is the domain model which contains a property named Amount.

###Filters:###

IFinancialRule<T> - https://github.com/Amila17/PipeAndFiltersDesignPattern/blob/master/src/PipeAndFiltersDesignPattern/Filters/IFinancialRule.cs

Is the programming contract for the filters that could be applied for any financial process eg: withdrawal or deposit.

#####Implementations of the IFinancialRule<T> are:####

######Site1######

######Site2

###Pipe:###

IPipeline<T> - https://github.com/Amila17/PipeAndFiltersDesignPattern/blob/master/src/PipeAndFiltersDesignPattern/Pipeline/IPipeline.cs

Is the programming contract for the pipeline that allows the registrations of the filters (IFinancialRule<T>) implementations and executes these implementations to return back a final result.

Pipeline<T> - https://github.com/Amila17/PipeAndFiltersDesignPattern/blob/master/src/PipeAndFiltersDesignPattern/Pipeline/Pipeline.cs

Is the implementation for the IPipeline<T> interface.

Context<T> - https://github.com/Amila17/PipeAndFiltersDesignPattern/blob/master/src/PipeAndFiltersDesignPattern/Pipeline/Context.cs

Is the class that carries any required objects through the pipeline. This class also keeps the state of any errors that occur during the filter execution process.

###Autofac Tenant Identification Strategy ###

SimpleTenantIdentificationStrategy - https://github.com/Amila17/PipeAndFiltersDesignPattern/blob/master/src/PipeAndFiltersDesignPattern/Autofac.Tenant/SimpleTenantIdentificationStrategy.cs

Implements ITenantIdentificationStrategy. This class enables autofac to identify which tenant is in the current context of the application. A ideal implementation would be to extract a value from the current http request to identify the tenant.

More information on this could be found here: http://autofac.readthedocs.org/en/latest/advanced/multitenant.html?highlight=multitenant#tenant-identification


###Composition###

####Non IoC Composition####

The following code block demonstrates how all of the above code composes together to bring about the Pipe and Filters design pattern into action:

//Valid withdrawal limit is amount > 100 and amount < 1000.

var validWithdrawal = new Withdrawal() {Amount = 150};
var inValidWithdrawalLimit = new Withdrawal() {Amount = 50};

IFinancialRule<Withdrawal> dailyLimit = new DailyLimit();
IFinancialRule<Withdrawal> belowMinimumAllowed = new BelowMinimumAllowed();
IFinancialRule<Withdrawal> aboveMaximumAllowed = new AboveMaximum();

IPipeline<Withdrawal> withdrawalPipeline = new Pipeline<Withdrawal>();
withdrawalPipeline.Register(dailyLimit)
    .Register(belowMinimumAllowed)
    .Register(aboveMaximumAllowed);

var validContext = new Context<Withdrawal>() {item = validWithdrawal};
var result = withdrawalPipeline.Execute(validContext);
Console.WriteLine(string.Format("The request for withdrawal is valid? {0}", result));

var invalidContext = new Context<Withdrawal> {item = inValidWithdrawalLimit};
result = withdrawalPipeline.Execute(invalidContext);
Console.WriteLine(string.Format("The request for the withdrawal is valid? {0}", result));

####IoC Composition####

The following code block demonstrates how to register all of the above code with Autofac and use its ability to resolve different filters for different tenants with the use of Autofac.Multitenants package.

var builder = new ContainerBuilder();

builder.RegisterType<Pipeline<Withdrawal>>().As<IPipeline<Withdrawal>>();

var container = builder.Build();

var tenantIdentifier = new SimpleTenantIdentificationStrategy();

var mtc = new MultitenantContainer(tenantIdentifier, container);

mtc.ConfigureTenant("1", cb => cb.Register(ctx => 
    new Pipeline<Withdrawal>()
    .Register(new DailyLimit100())
    .Register(new AboveMaximum1000())
    .Register(new BelowMinimumAllowed100())).As<IPipeline<Withdrawal>>());

mtc.ConfigureTenant("2", cb => cb.Register(ctx => 
    new Pipeline<Withdrawal>()
    .Register(new DailyLimit50())
    .Register(new AboveMaximum100())
    .Register(new BelowMinimumAllowed20())).As<IPipeline<Withdrawal>>());


======== Tenant 1 (Site 1) Registrations ===========
tenantIdentifier.SetTenant(TenantName.Site1);

var withdrawalPipelineTenant1 = mtc.Resolve<IPipeline<Withdrawal>>();

//Valid withdrawal limit is amount > 100 and amount < 1000.
var validWithdrawal = new Withdrawal() { Amount = 150 };
var inValidWithdrawalLimit = new Withdrawal() { Amount = 50 };

var validContext = new Context<Withdrawal>() { item = validWithdrawal };
var result = withdrawalPipelineTenant1.Execute(validContext);
Console.WriteLine(string.Format("The request for Tenant 1 withdrawal is valid? {0}", result));

var invalidContext = new Context<Withdrawal> { item = inValidWithdrawalLimit };
result = withdrawalPipelineTenant1.Execute(invalidContext);
Console.WriteLine(string.Format("The request for Tenant 1 withdrawal is valid? {0}", result));

========== Tenant 2 (Site 2) Registrations ===========
tenantIdentifier.SetTenant(TenantName.Site2);

var withdrawalPipelineTenant2 = mtc.Resolve<IPipeline<Withdrawal>>();

//Valid withdrawal limit is amount > 50 and amount < 100.
validWithdrawal = new Withdrawal() { Amount = 60 };
inValidWithdrawalLimit = new Withdrawal() { Amount = 10 };

validContext = new Context<Withdrawal>() { item = validWithdrawal };
result = withdrawalPipelineTenant2.Execute(validContext);
Console.WriteLine(string.Format("The request for Tenant 2 withdrawal is valid? {0}", result));

invalidContext = new Context<Withdrawal> { item = inValidWithdrawalLimit };
result = withdrawalPipelineTenant2.Execute(invalidContext);
Console.WriteLine(string.Format("The request for Tenant 2 withdrawal is valid? {0}", result));

Hope this helps in understanding the design pattern.

P G Amila Prabandhika

About

This repository contains a demonstration on how to use the Pipe and Filters design pattern.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages