ArrayCollection: filterFuntion with multiple filter functions using decorator pattern

I was looking for an elegant solution to implement multiple filter functions on an ArrayCollection (which provides a method filterFunction() that can be assigned dynamically in order to filter data inside the collection). The first and only valid solution I found was that one from Cristian Rotundu, he has extended ArrayCollection class providing a filterFunctions properties which accepts an Array of functions which will be executed in sequence (into a loop) once filterFunction is triggered. Anyway I didn’t want to subclass ArrayCollection and by using the decorator pattern I implemented my own multiple filters version.

So, this is what I done:

  1. I defined an interface IFilter, which declares only one method: apply()
  2. I defined a dummy Filter class (which implements IFilter in a basic way just to agree to the interface), that is used as a basic empty filter to decorate. It also has a constant called ALL_VALUES which is used as a wildcard for filters (it’s a simple string with value “*”, which means “all values are allowed”)
  3. I defined an abstract AbstractFilterDecorator class
  4. I created as many subclass of AbstractFilterDecorator as the filters I need (yes I treat filters as classes not mere functions)

The implementation code is the following:

var data:ArrayCollection = ArrayCollection(grid.dataProvider);
var filter:IFilter = new Filter();
				
filter = new LevelFilter(filter, levelValue);
filter = new CategoryFilter(filter, categoryValue);
filter = new DateFilter(filter, dateValue, "DD/MM/YY");
				
data.filterFunction = filter.apply;
data.refresh();

The filter object is wrapped by decorators which all accepts 2 common arguments: an IFilter reference and an Object representing a value. The DateFilter has a third parameter which is used to configure an internal DateFormatter (from mx.formatters package).
I’m pretty satisfied :)
Uh… and if you are worried about performance, it is fast enough because filter object are created once and then the function assigned to filterFunction is a reference to the resulting decorated filter.

UPDATE:
I realized a very simple example application which can be downloaded here.
This following is the content of the mxml file:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">

	<mx:Script>
		<![CDATA[
		
			import mx.collections.ArrayCollection;
			import com.daveoncode.filters.*;
			
			private function applyFilters():void {
				
				var data:ArrayCollection  = ArrayCollection(userGrid.dataProvider);
				var filter:IFilter = new Filter();
				
				filter = new AgeFilter(filter, ageFilterValue.text);
				filter = new DateFilter(filter, dateFilterValue.selectedDate);
				filter = new SexFilter(filter, sexFilterValue.value);
				
				data.filterFunction = filter.apply;
				data.refresh();
				
			}
			
		]]>
	</mx:Script>
	
	<mx:Panel title="Filters" width="600">
		<mx:Form>
			<mx:FormItem label="Age:">
				<mx:TextInput id="ageFilterValue" width="30" />
			</mx:FormItem>
			<mx:FormItem label="Sex:">
				<mx:ComboBox id="sexFilterValue" dataProvider="{[{data: Filter.ALL_VALUES, label: 'ALL'}, {data: 'm', label: 'Male'}, {data: 'f', label: 'Female'}]}" />
			</mx:FormItem>
			<mx:FormItem label="Join date:">
				<mx:DateField id="dateFilterValue" formatString="DD/MM/YY" />
			</mx:FormItem>
			<mx:FormItem>
				<mx:Button label="Apply filters" click="{this.applyFilters()}" />
			</mx:FormItem>
		</mx:Form>
	</mx:Panel>
	
	<mx:Panel title="Users" width="600">
		<mx:DataGrid id="userGrid" width="100%">
			<mx:dataProvider>
				<mx:ArrayCollection>
					<mx:Array>
						<mx:Object age="24" sex="f" name="Susan" joinDate="{new Date(2007, 5, 15)}" />
						<mx:Object age="36" sex="f" name="Ashley" joinDate="{new Date(1998, 7, 20)}" />
						<mx:Object age="24" sex="f" name="Jennifer" joinDate="{new Date(2001, 3, 24)}" />
						<mx:Object age="19" sex="f" name="Emma" joinDate="{new Date(2002, 3, 24)}" />
						<mx:Object age="44" sex="f" name="Carol" joinDate="{new Date(1999, 9, 16)}" />
						<mx:Object age="28" sex="m" name="Peter" joinDate="{new Date(2005, 3, 12)}" />
						<mx:Object age="35" sex="m" name="Mike" joinDate="{new Date(2008, 10, 10)}" />
						<mx:Object age="26" sex="m" name="Dave" joinDate="{new Date(2008, 10, 10)}" />
						<mx:Object age="44" sex="m" name="William" joinDate="{new Date(2004, 9, 16)}" />
						<mx:Object age="24" sex="m" name="Sean" joinDate="{new Date(2006, 3, 24)}" />
					</mx:Array>
				</mx:ArrayCollection>
			</mx:dataProvider>
		</mx:DataGrid>
	</mx:Panel>
	
</mx:Application>