diff --git a/DependencyInjection/Builder/ClassFilterBuilder.php b/DependencyInjection/Builder/ClassFilterBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..d3020bd7302aa35827f5ada21da94e9e15ee4f5d
--- /dev/null
+++ b/DependencyInjection/Builder/ClassFilterBuilder.php
@@ -0,0 +1,140 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\DependencyInjection\Builder;
+
+use Irstea\PlantUmlBundle\Model\Filter\ClassFilter;
+use Irstea\PlantUmlBundle\Model\Filter\Composite\AllFilter;
+use Irstea\PlantUmlBundle\Model\Filter\DirectoryFilter;
+use Irstea\PlantUmlBundle\Model\Filter\NamespaceFilter;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Description of ClassFilterBuilder
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class ClassFilterBuilder
+{
+    /**
+     * @var ContainerBuilder
+     */
+    private $container;
+
+    /**
+     * @var Reference[]
+     */
+    private $filters = [];
+
+    /**
+     * @var string[]
+     */
+    static private $filterClasses = [
+        'classes'     => ClassFilter::class,
+        'directories' => DirectoryFilter::class,
+        'namespaces'  => NamespaceFilter::class
+    ];
+
+    /**
+     * @param \Irstea\PlantUmlBundle\DependencyInjection\Builder\ContainerBuilder $container
+     */
+    public function __construct(ContainerBuilder $container)
+    {
+        $this->container = $container;
+    }
+
+    /**
+     * @param array $config
+     * @return Reference
+     */
+    public function build(array $config)
+    {
+        $filters = $this->normalize(array_intersect_key($config, ['include' => true, 'exclude' => true]));
+        if ($filters === null) {
+            return null;
+        }
+
+        $hash = sha1(serialize($filters));
+        if (!key_exists($hash, $this->filters)) {
+            return $this->filters[$hash] = $this->doBuild("irstea.plant_uml.filters.$hash", $filters);
+        }
+
+        return $this->filters[$hash];
+    }
+
+    /**
+     * @param mixed $data
+     * @return mixed
+     */
+    protected function normalize($data)
+    {
+        if ($data === null || $data === []) {
+            return null;
+        }
+        if (is_array($data)) {
+            $res = [];
+            foreach($data as $k => $v) {
+                $normalized = $this->normalize($v);
+                if (!empty($normalized)) {
+                    $res[$k] = $normalized;
+                }
+            }
+            return empty($res) ? null : $res;
+        }
+        return $data;
+    }
+
+    /**
+     * @param type $id
+     * @param array $config
+     * @return Reference
+     */
+    protected function doBuild($id, array $config)
+    {
+        $filters = [];
+
+        if (isset($config['include'])) {
+            $this->buildSubFilter($filters, "$id.include", $config['include'], false);
+        }
+        if (isset($config['exclude'])) {
+            $this->buildSubFilter($filters, "$id.exclude", $config['exclude'], true);
+        }
+
+        if (empty($filters)) {
+            return null;
+        }
+
+        if (count($filters) === 1) {
+            return $filters[0];
+        }
+
+        $this->container->setDefinition($id, new Definition(AllFilter::class, [$filters]));
+        return new Reference($id);
+    }
+
+    /**
+     * @param array $filters
+     * @param string $id
+     * @param array $config
+     * @param bool $notFound
+     */
+    protected function buildSubFilter(array &$filters, $id, array $config, $notFound)
+    {
+        foreach (self::$filterClasses as $key => $class) {
+            if (!isset($config[$key])) {
+                continue;
+            }
+            $subId = "$id.$key";
+            $def = new Definition($class, [$config[$key], $notFound]);
+            $this->container->setDefinition($subId, $def);
+            $filters[] = new Reference($subId);
+        }
+    }
+}
diff --git a/DependencyInjection/Builder/GraphDefinitionBuilder.php b/DependencyInjection/Builder/GraphDefinitionBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..1be9d730bac9c51fa5b9a1a59e672467df0e626f
--- /dev/null
+++ b/DependencyInjection/Builder/GraphDefinitionBuilder.php
@@ -0,0 +1,253 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\DependencyInjection\Builder;
+
+use Irstea\PlantUmlBundle\Doctrine\EntityFinder;
+use Irstea\PlantUmlBundle\Finder\ClassFinder;
+use Irstea\PlantUmlBundle\Finder\FilteringFinder;
+use Irstea\PlantUmlBundle\Model\ClassVisitor;
+use Irstea\PlantUmlBundle\Model\Graph;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Definition;
+use Symfony\Component\DependencyInjection\DefinitionDecorator;
+use Symfony\Component\DependencyInjection\Reference;
+
+/**
+ * Description of GraphDefinitionBuilder
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class GraphDefinitionBuilder
+{
+    /**
+     * @var ContainerBuilder
+     */
+    private $container;
+
+    /**
+     * @var string
+     */
+    private $baseId;
+
+    /**
+     * @var array
+     */
+    private $config;
+
+    /**
+     * @var ClassFilterBuilder
+     */
+    private $filterBuilder;
+
+    /**
+     * @var Reference
+     */
+    private $entityManager;
+
+    /**
+     *
+     * @var Definition
+     */
+    private $definition = null;
+
+    /**
+     *
+     * @param ContainerBuilder $container
+     * @param string $baseId
+     * @param array $config
+     */
+    public function __construct(ContainerBuilder $container, $baseId, array $config, ClassFilterBuilder $filterBuilder)
+    {
+        $this->container = $container;
+        $this->baseId = $baseId;
+        $this->config = $config;
+        $this->filterBuilder = $filterBuilder;
+
+        $emId = $config['sources']['entity_manager'];
+        $this->entityManager = new Reference("doctrine.orm.${emId}_entity_manager");
+    }
+
+    /**
+     * @return Definition
+     */
+    public function build()
+    {
+        if (!$this->definition) {
+            return $this->definition = $this->doBuild();
+        }
+        return $this->definition;
+    }
+
+    /**
+     * @return Definition
+     */
+    protected function doBuild()
+    {
+        list($source, $sourceFilter) = $this->buildSources();
+        
+        $layoutFilter = $this->filterBuilder->build($this->config['layout']) ?: $sourceFilter;
+        $decorator = $this->buildFilteredDecorator();
+        $namespace = $this->buildNamespace();
+
+        $visitor = $this->setDefinition("visitor", ClassVisitor::class, $decorator, $layoutFilter, $namespace);
+
+        return new Definition(Graph::class, [$visitor, $source]);
+    }
+
+    /**
+     * @return Refernce[]
+     */
+    protected function buildSources()
+    {
+        $finder = $this->buildFinder();
+        $filter = $this->filterBuilder->build($this->config['sources']);
+
+        if ($filter) {
+            $filtered = $this->setDefinition("finder", FilteringFinder::class, $finder, $filter);
+            return [$filtered, $filter];
+        }
+
+        return [$finder, null];
+    }
+
+    /**
+     * @return Reference
+     */
+    protected function buildFinder()
+    {
+        $config = $this->config['sources'];
+
+        switch($config['type']) {
+            case 'entities':
+                return $this->setDefinition("finder.entities", EntityFinder::class, $this->entityManager);
+            case 'classes':
+                return $this->setDefinition("finder.classes", ClassFinder::class, $config['directories']);
+        }
+    }
+
+    /**
+     * @return Reference
+     */
+    protected function buildFilteredDecorator()
+    {
+        $decorator = $this->buildDecorator();
+        if (!$decorator) {
+            return $decorator;
+        }
+
+        $filter = $this->filterBuilder->build($this->config['decoration']);
+        if (!$filter) {
+            return $decorator;
+        }
+
+        return $this->setDefinitionDecorator('decorator', 'irstea.plant_uml.decorator.filtered.template', $decorator, $filter);
+    }
+
+    /**
+     * @return Reference
+     */
+    protected function buildDecorator()
+    {
+        $config = $this->config['decoration']['decorators'];
+
+        if (empty($config)) {
+            return null;
+        }
+
+        if (count($config) === 1) {
+            return $this->buildTypedDecorator($config[0]);
+        }
+
+        $decorators = [];
+        foreach ($config as $type) {
+            $decorators[] = $this->buildTypedDecorator($type);
+        }
+
+        return $this->setDefinitionDecorator(
+            'decorator.all',
+            'irstea.plant_uml.decorator.composite.template',
+            $decorators
+        );
+    }
+
+    /**
+     * @param string $type
+     * @return Reference
+     */
+    protected function buildTypedDecorator($type)
+    {
+        if (in_array($type, ['entity', 'associations', 'fields'])) {
+            return $this->setDefinitionDecorator(
+                "decorator.$type",
+                "irstea.plant_uml.decorator.$type.template",
+                $this->entityManager
+            );
+        }
+
+        return new Reference("irstea.plant_uml.decorator.$type");
+    }
+
+    /**
+Å“     * @return Reference
+     */
+    protected function buildNamespace()
+    {
+        $type = $this->config['layout']['namespaces'];
+        
+        if ($type === "entities") {
+            return $this->setDefinitionDecorator(
+                "namespace.$type",
+                "irstea.plant_uml.namespaces.$type.template",
+                $this->entityManager
+            );
+        }
+
+        return new Reference("irstea.plant_uml.namespaces.$type");
+    }
+
+    /**
+     * @param string $localId
+     * @param string|Definition $classOrDef
+     * @param array ...$arguments
+     * @return Reference
+     */
+    protected function setDefinition($localId, $classOrDef, ...$arguments)
+    {
+        if ($classOrDef instanceof Definition) {
+            $definition = $classOrDef;
+        } else {
+            $definition = new Definition($classOrDef, $arguments);
+        }
+        $id = $this->globalId($localId);
+        $this->container->setDefinition($id, $definition);
+        return new Reference($id);
+    }
+
+    /**
+     * @param string $localId
+     * @param string $templateId
+     * @param array ...$arguments
+     * @return Reference
+     */
+    protected function setDefinitionDecorator($localId, $templateId, ...$arguments)
+    {
+        $def = new DefinitionDecorator($templateId);
+        $def->setArguments($arguments);
+        return $this->setDefinition($localId, $def);
+    }
+
+    /**
+     * @param string $localId
+     * @return string
+     */
+    protected function globalId($localId)
+    {
+        return "{$this->baseId}.$localId";
+    }
+}
diff --git a/DependencyInjection/IrsteaPlantUmlExtension.php b/DependencyInjection/IrsteaPlantUmlExtension.php
index 6c8a63cc78cd0504914ed34a16462b23a393b92c..3adc4aa357143f3b75f3f0f4ddf6c33c50d36964 100644
--- a/DependencyInjection/IrsteaPlantUmlExtension.php
+++ b/DependencyInjection/IrsteaPlantUmlExtension.php
@@ -8,18 +8,12 @@
 
 namespace Irstea\PlantUmlBundle\DependencyInjection;
 
-use Irstea\PlantUmlBundle\Doctrine\EntityFinder;
-use Irstea\PlantUmlBundle\Finder\ClassFinder;
-use Irstea\PlantUmlBundle\Finder\FilteringFinder;
-use Irstea\PlantUmlBundle\Model\ClassVisitor;
-use Irstea\PlantUmlBundle\Model\Graph;
+use Irstea\PlantUmlBundle\DependencyInjection\Builder\ClassFilterBuilder;
+use Irstea\PlantUmlBundle\DependencyInjection\Builder\GraphDefinitionBuilder;
 use Symfony\Component\Config\FileLocator;
 use Symfony\Component\DependencyInjection\ContainerBuilder;
-use Symfony\Component\DependencyInjection\Definition;
-use Symfony\Component\DependencyInjection\DefinitionDecorator;
 use Symfony\Component\DependencyInjection\Extension\Extension;
 use Symfony\Component\DependencyInjection\Loader;
-use Symfony\Component\DependencyInjection\Reference;
 
 /**
  * Description of IrsteaPlantUmlExtension
@@ -41,184 +35,13 @@ class IrsteaPlantUmlExtension extends Extension
         $container->setParameter('irstea_plant_uml.binaries.dot', $config['binaries']['dot']);
         $container->setParameter('irstea_plant_uml.output.directory', $config['output']['directory']);
         $container->setParameter('irstea_plant_uml.output.format', $config['output']['format']);
-
-        foreach($config['graphs'] as $key => $graph) {
-            $this->loadGraph($key, $graph, $container);
-        }
         $container->setParameter('irstea_plant_uml.graph_keys', array_keys($config['graphs']));
-    }
-
-    public function loadGraph($key, array $config, ContainerBuilder $container)
-    {
-        $id = "irstea_plant_uml.graph.$key";
-
-        $emName = $config['sources']['entity_manager'];
-        $em = new Reference("doctrine.orm.${emName}_entity_manager");
-
-        list($source, $defaultFilter) = $this->loadSources($id, $em, $config['sources'], $container);
-
-        $visitor = $this->addService(
-            $container,
-            "$id.visitor",
-            ClassVisitor::class,
-            [
-                $this->loadDecorator($id, $em, $config['decoration'], $defaultFilter, $container),
-                $this->loadFilter($id, $config['layout'], $container),
-                $this->loadNamespace($id, $em, $config['layout']['namespaces'], $container)
-            ]
-        );
-
-        $container->setDefinition($id, new Definition(Graph::class, [$visitor, $source]))
-            ->setPublic(true)
-            ->setLazy(true);
-    }
-
-    /**
-     * @param string $id
-     * @param array $config
-     * @param ContainerBuilder $container
-     * @return Refernce[]
-     */
-    protected function loadSources($id, Reference $em, array $config, ContainerBuilder $container)
-    {
-        $finderId = "$id.finder";
 
-        $filter = $this->loadFilter($finderId, $config, $container);
-        if ($filter) {
-            $inner = $this->loadFinder("$finderId.inner", $em, $config, $container);
-            $finder = $this->addService($container, $finderId, FilteringFinder::class, [$inner, $filter]);
-        } else {
-            $finder = $this->loadFinder($finderId, $em, $config, $container);
+        $filterBuilder = new ClassFilterBuilder($container);
+        foreach ($config['graphs'] as $key => $graph) {
+            $id = "irstea_plant_uml.graph.$key";
+            $builder = new GraphDefinitionBuilder($container, $id, $graph, $filterBuilder);
+            $container->setDefinition($id, $builder->build());
         }
-
-        return [$finder, $filter];
-    }
-
-    /**
-     * @param string $id
-     * @param Reference $em
-     * @param array $config
-     * @param ContainerBuilder $container
-     * @return Reference
-     */
-    protected function loadFinder($id, Reference $em, array $config, ContainerBuilder $container)
-    {
-        switch($config['type']) {
-            case 'entities':
-                return $this->addService($container, $id, EntityFinder::class, [$em]);
-            case 'classes':
-                return $this->addService($container, $id, ClassFinder::class, [$config['directories']]);
-        }
-    }
-
-    /**
-     *
-     * @param string $id
-     * @param Reference $em
-     * @param array $config
-     * @param Reference $defaultFilter
-     * @param ContainerBuilder $container
-     * @return Reference
-     */
-    protected function loadDecorator($id, Reference $em, array $config, Reference $defaultFilter, ContainerBuilder $container)
-    {
-        if (empty($config['decorators'])) {
-            return new Reference('irstea.plant_uml.decorator.null');
-        }
-
-        $decoratorId = "$id.decorator";
-
-        $decorators = [];
-        foreach($config['decorators'] as $i => $type) {
-            $decorators[] = $this->loadTypedDecorator("$decoratorId.$i", $em, $type, $container);
-        }
-
-        if (count($decorators) === 1) {
-            $container->setAlias($decoratorId, "$decoratorId.0");
-        } else {
-            $container
-                ->setDefinition($decoratorId, new DefinitionDecorator('irstea.plant_uml.decorator.composite.template'))
-                ->setArguments([$decorators]);
-        }
-
-        $filter = $this->loadFilter($decoratorId, $config, $container) ?: $defaultFilter;
-        if ($filter) {
-            $container
-                ->setDefinition("$decoratorId.decorator", new DefinitionDecorator('irstea.plant_uml.decorator.filtered.template'))
-                ->setDecoratedService($decoratorId, "inner_decorator")
-                ->setArguments([new Reference("inner_decorator"), $filter]);
-        }
-
-        return new Reference($decoratorId);
-    }
-
-    /**
-     * @param string $id
-     * @param Reference $em
-     * @param string $type
-     * @param ContainerBuilder $container
-     * @return Reference
-     */
-    protected function loadTypedDecorator($id, Reference $em, $type, ContainerBuilder $container)
-    {
-        if (in_array($type, ['entity', 'associations', 'fields'])) {
-            $container
-                ->setDefinition($id, new DefinitionDecorator("irstea.plant_uml.decorator.$type.template"))
-                ->setArguments([$em]);
-            return new Reference($id);
-        }
-
-        return new Reference("irstea.plant_uml.decorator.$type");
-    }
-
-    /**
-     * @param string $id
-     * @param Reference $em
-     * @param string $type
-     * @param ContainerBuilder $container
-     * @return Reference
-     */
-    protected function loadNamespace($id, Reference $em, $type, ContainerBuilder $container)
-    {
-        if ($type === "entities") {
-            $namespaceId = "$id.namespace";
-            $container
-                ->setDefinition($namespaceId, new DefinitionDecorator('irstea.plant_uml.namespaces.entities.template'))
-                ->setArguments([$em]);
-            return new Reference($namespaceId);
-        }
-
-        return new Reference("irstea.plant_uml.namespaces.$type");
-    }
-
-    /**
-     * @param string $id
-     * @param array $config
-     * @param ContainerBuilder $container
-     * @return Reference
-     */
-    protected function loadFilter($id, array $config, ContainerBuilder $container)
-    {
-        $filterId = "$id.filter";
-        $container
-            ->setDefinition($filterId, new DefinitionDecorator("irstea.plant_uml.filter.template"))
-            ->setArguments([
-                isset($config['include']) ? $config['include'] : [],
-                isset($config['exclude']) ? $config['exclude'] : [],
-            ]);
-        return new Reference($filterId);
-    }
-
-    /**
-     *
-     * @param ContainerBuilder $container
-     * @param string $id
-     * @param Definition $def
-     * @return Reference
-     */
-    protected function addService(ContainerBuilder $container, $id, $class, array $arguments = [])
-    {
-        $container->setDefinition($id, new Definition($class, $arguments));
-        return new Reference($id);
     }
 }
diff --git a/Resources/config/services.yml b/Resources/config/services.yml
index c6d838724313eab97a54775019ba4892f5b92fe7..4459e3623eb59004f438f4a49cc005be35e0b192 100644
--- a/Resources/config/services.yml
+++ b/Resources/config/services.yml
@@ -1,16 +1,6 @@
 parameters: ~
 
 services:
-    irstea.plant_uml.filter.factory:
-        class: Irstea\PlantUmlBundle\Factory\FilterFactory
-        arguments: [@kernel]
-
-    irstea.plant_uml.filter.template:
-        class: Irstea\PlantUmlBundle\Model\ClassFilterInterface
-        abstract: true
-        factory: ["@irstea.plant_uml.filter.factory", create]
-        public: false
-
     irstea.plant_uml.finder.classes.template:
         class: Irstea\PlantUmlBundle\Finder\ClassFinder
         abstract: true