Modifying the Filter Pattern with Generic Lambda Expressions
We can optimize the Pipeline & Filter pattern (pipeline and filters) by reducing the amount of code required to implement it by using a lambda expression (simplified notation of anonymous methods) as a specific filter condition. As an example to demonstrate this concept, a WPF application with a user interface was chosen. Here is its source code.
Pipeline & Filter pattern
Typically, within this pattern, an interface is implemented for each new filter. Instead of implementing an interface for each filter condition, you can use a generic lambda expression as input to the filter pipeline. This will result in less code. Below is a class diagram:
ConditionAggregator
is the pipelined class that holds the collection Condition<T>
… Filter<T>
owns ConditionAggregator
or Condition<T>
to apply filtering conditions to the dataset. When the apply function is called Filter<T>
, the check method is executed ICondition<T>
… ConditionAggregator<T>
has an event OnFilterChanged
… It fires when the value of a collection or condition changes in the classes of the view model. The next section will describe the use of the Filter pattern by the view model.
The code
Use in the view model
An explanation of the MVVM pattern can be found at this link… One of the responsibilities of the View Model in MVVM is to handle user interaction and data changes. In our case, changes in the values of the filtering conditions must be passed to the business layer in order to apply filters to a specific collection of data. Changing the value of a condition in the view model streams the event ConditionAggregator<T>
OnFilterChanged
subscribed to by the apply filter method. Below is a class diagram of the view model.
Entity class Employee
created to store information about employees. Generic
a type T
design pattern Filter
will be replaced by class Employee
… EmployeeList
contains a list of employee data and filters to apply. The constructor of the class gets the list of conditions and navigates to the list of filters.
public EmployeeList(IEmployeesRepository repository, ConditionAggregator<employee> conditionAggregator)
{
this.repository = repository;
this.filters = new ConcreteFilter<employee>(conditionAggregator);
conditionAggregator.OnFilterChanged += this.FilterList;
_ = initAsync();
}
Method FilterList
subscribed to the event OnFilterChanged
to apply filters to data when a condition or value changes.
private void FilterList()
{
this.Employees = this.filters.Apply(this.employeesFullList);
}
EmployeesViewModel
connected to the user interface. This example shows only one property filter EmployeeTypeselected
but in ConditionAggregator
many filters can be passed. The next piece of code is the constructor method that registers the filter condition.
public EmployeesViewModel(IEmployeesRepository repository)
{
this.repository = repository;
Condition<employee> filterEmployee = new Condition<employee>((e) => e.employeeCode == this.EmployeeTypeSelected);
this.conditionAggregator = new ConditionAggregator<employee>(new List<condition<employee>> { filterEmployee });
this.EmployeeList = new EmployeeList(repository, this.conditionAggregator);
}
</condition<employee></employee></employee></employee>
The condition is passed as a lambda expression. There can be any number of them, since the constructor ConditionAggregator
takes a list of filtering conditions. The main goal of reducing the code required to create a specific class of filter conditions has been achieved.
Application architecture
WPF.Demo.DataFilter
is a WPF UI view. It has one grid and one combo box for filtering. Project WPF.Demo.DataFilter.ViewModels
processes data, filters changes, and reloads data to update the user interface. Project WPF.Demo.DataFilter.Common
is a complete implementation of the Pipeline & Filter pattern. WPF.Demo.DataFilter.DAL
loads a simple json file as data store.
This is the main interface:
The translation of the article was prepared in anticipation of the start of the course “Architecture and Design Patterns”… And right now we invite everyone to free demo lesson within the framework of which we will discuss the purpose and structure of the “Interpreter” pattern, the Backus-Nauer forms, lexical, syntactic and semantic analyzes, as well as analyze practical examples. You can sign up for a lesson by link…