Ve webových aplikacích se často objevují funkcionality, které je potřeba vykonat před spuštěním controlleru (z návrhového vzoru MVC). Mám na mysli například logování přístupu, dekompresi dat z požadavku, kódování znaků, kontrolu IP adresy, kontrolu session, zpracování cookies, atd.. Návrhový vzor Interception Filter ukazuje způsob, kterým je možné tyto nizkoúrovňové funkce zapouzdřit a využívat v aplikaci.

Je zřejmé, že tyto funkce nepatří do aplikační logiky, ale jedná se o jakési předzpracování, které navíc bývá společné pro všechny stránky. Z těchto důvodů je dobré tyto funkce umístit na nějaké centrální místo a vyhnout se tak duplicitě kódu.

Mnohé nízkoúrovňové funkce spolu vůbec nesouvisí (kontrola IP, zjištění typu browseru) a proto je vhodné zapouzdřit každou tuto funkci do samostatného modulu a maximalizovat tak znovupoužitelnost kódu. Navíc je pak možné tyto moduly přidávat a odebírat z aplikace podle potřeby. (Pokud to naprogramujeme šikovně, můžeme moduly přidávat a odebírat až v době rozmístění, například s využitím konfiguračního souboru.)

Je potřeba mít na paměti, že tyto funkce jsou vykonávány při každém požadavku na stránku, proto by měly být co nejvýkonější, neměly by obsahovat zbytečnosti a neměly by přistupovat k pomalým uložištím.

Jak by to teda mělo fungovat?
Jednotlivé nizkoúrovňové funkce si můžeme představit jako filtry, které se aplikují před spuštěním controlleru (případně i po jeho spuštění = výstupní filtry). Tyto filtry tvoří jakýsi řetěz, jehož články můžeme podle našich potřeb přidávat a odebírat. Je více způsobů jak řetěz filtrů implementovat. Já se pokusím naznačit dva způsoby. Jeden využívá objekt ŘetězFiltrů obsahující kolekci filtrů, druhý využívá návrhový vzor decorator.

Implementace pomocí kolekce

ObsluhaPožadavků přijme požadavek a předá řízení ŘetězuFiltrů. Tento objekt prochází svou kolekci filtrů a na kždém z nich zavolá metodu filtruj. Po tom, co jsou provedeny všechny filtry, předá ObsluhaPožadavků řízení controlleru.

Implementace pomocí návrhového vzoru decorator

Tato implementace návrhového vzoru Intercepting Filter obaluje front controller pomocí vzoru decorator (více zde nebo zde) jednotlivými filtry. Hlavní myšlenka je v tom, že filtr i front controller mají stejné rozhraní (implementují stejné rozhraní, nebo dědí ze stejné třídy) a jsou tedy zaměnitelné. Filtr tedy může obalit front controller. Tento filtr může být obalen dalším filtrem (implementují stejné rozhraní), atd. Tímto způsobem se vytvoří obdobný řetěz filtrů jako v předchozí implementaci.