diff --git a/Command/EntitySchemaCommand.php b/Command/EntitySchemaCommand.php
index 3922e7c83accfb67fbe4e0f370a8f9370581cfaa..2e86adf347863fd6749dd4753a9c6b01de03c238 100644
--- a/Command/EntitySchemaCommand.php
+++ b/Command/EntitySchemaCommand.php
@@ -8,7 +8,9 @@ namespace Irstea\PlantUmlBundle\Command;
 
 use Doctrine\ORM\EntityManagerInterface;
 use Doctrine\ORM\Mapping\ClassMetadata;
+use Irstea\PlantUmlBundle\Model\Namespace_;
 use Irstea\PlantUmlBundle\Model\Orm\EntityVisitor;
+use Irstea\PlantUmlBundle\Writer\OutputWriter;
 use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
 use Symfony\Component\Console\Input\InputArgument;
 use Symfony\Component\Console\Input\InputInterface;
@@ -50,11 +52,9 @@ class EntitySchemaCommand extends ContainerAwareCommand
             $visitor->visitClass($metadata->getName());
         }
 
-        $stream = fopen("php://output", "wt");
-        fputs($stream, "@startuml\n");
-        fputs($stream, "set namespaceSeparator .\n");
-        $visitor->outputTo($stream);
-        fputs($stream, "@enduml\n");
-        fclose($stream);
+        $writer = new OutputWriter($output);
+        $writer->write("@startuml\n");
+        $visitor->outputTo($writer);
+        $writer->write("@enduml\n");
     }
 }
diff --git a/Model/AbstractNamespace.php b/Model/AbstractNamespace.php
new file mode 100644
index 0000000000000000000000000000000000000000..783846d83d343b70bf450c01b72a26d0c29a89a9
--- /dev/null
+++ b/Model/AbstractNamespace.php
@@ -0,0 +1,91 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model;
+
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
+
+/**
+ * Description of Namespace
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+abstract class AbstractNamespace implements UmlComponentInterface, NamespaceInterface
+{
+    /**
+     * @var UmlNodeInterface[]
+     */
+    private $nodes = [];
+
+    /**
+     * @var NamespaceInterface
+     */
+    private $children = [];
+
+    /**
+     *
+     * @param UmlNodeInterface $node
+     */
+    public function addNode(UmlNodeInterface $node)
+    {
+        $this->nodes[] = $node;
+        return $this;
+    }
+
+    /**
+     * @param type $namespaceName
+     * @return NamespaceInterface
+     */
+    public function getNamespace($namespaceName)
+    {
+        $namespaceName = trim($namespaceName, '\\');
+        if (!$namespaceName) {
+            return $this;
+        }
+        @list($head, $tail) = explode('\\', $namespaceName, 2);
+        if (!isset($this->children[$head])) {
+            $this->children[$head] = new Namespace_($this, $head);
+        }
+        if (empty($tail)) {
+            return $this->children[$head];
+        }
+        return $this->children[$head]->getNamespace($tail);
+    }
+
+    /**
+     * @param WriterInterface $writer
+     * @return self
+     */
+    protected function outputNodesTo(WriterInterface $writer)
+    {
+        foreach ($this->nodes as $node) {
+            $node->outputTo($writer);
+        }
+        return $this;
+    }
+
+    /**
+     * @param WriterInterface $writer
+     * @return self
+     */
+    protected function outputChildrenTo(WriterInterface $writer)
+    {
+        foreach ($this->children as $child) {
+            $child->outputTo($writer);
+        }
+        return $this;
+    }
+
+    /**
+     * @return bool
+     */
+    protected function isEmpty()
+    {
+        return empty($this->children) && empty($this->nodes);
+    }
+}
diff --git a/Model/Arrow/BaseArrow.php b/Model/Arrow/BaseArrow.php
index 432ffe631f6694b254adcde6ebb965b7935970a9..5ba6bc8ac7976ff5a28188e5ff3b10756e8ce33b 100644
--- a/Model/Arrow/BaseArrow.php
+++ b/Model/Arrow/BaseArrow.php
@@ -8,15 +8,16 @@
 
 namespace Irstea\PlantUmlBundle\Model\Arrow;
 
-use Irstea\PlantUmlBundle\Model\UmlComponentInterface;
+use Irstea\PlantUmlBundle\Model\UmlArrowInterface;
 use Irstea\PlantUmlBundle\Model\UmlNodeInterface;
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
 
 /**
  * Description of Arrow
  *
  * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
  */
-class BaseArrow implements UmlComponentInterface
+class BaseArrow implements UmlArrowInterface
 {
     /**
      * @var UmlNodeInterface
@@ -41,24 +42,27 @@ class BaseArrow implements UmlComponentInterface
         $this->label  = $label;
     }
 
-    public function outputTo($stream)
+    public function outputTo(WriterInterface $writer)
     {
-        $this->source->outputAliasTo($stream);
-        $this->outputLinkTo($stream);
-        $this->target->outputAliasTo($stream);
-        $this->outputLabelTo($stream);
-        fputs($stream, "\n");
+        $this->source->outputAliasTo($writer);
+        $this->outputLinkTo($writer);
+        $this->target->outputAliasTo($writer);
+        $this->outputLabelTo($writer);
+        $writer->write("\n");
+        return $this;
     }
 
-    protected function outputLabelTo($stream)
+    protected function outputLabelTo(WriterInterface $writer)
     {
         if ($this->label) {
-            fputs($stream, " : {$this->label}");
+            $writer->printf(" : %s", $this->label);
         }
+        return $this;
     }
 
-    protected function outputLinkTo($stream)
+    protected function outputLinkTo(WriterInterface $writer)
     {
-        fputs($stream, " ".$this->link." ");
+        $writer->printf(" %s ", $this->link);
+        return $this;
     }
 }
diff --git a/Model/ClassVisitor.php b/Model/ClassVisitor.php
index 4454140d4482f2d5e21745fd68610609f0905fa3..08553b628184db102213880602a5ecf04120081a 100644
--- a/Model/ClassVisitor.php
+++ b/Model/ClassVisitor.php
@@ -11,6 +11,7 @@ namespace Irstea\PlantUmlBundle\Model;
 use Irstea\PlantUmlBundle\Model\Node\Class_;
 use Irstea\PlantUmlBundle\Model\Node\Interface_;
 use Irstea\PlantUmlBundle\Model\Node\Trait_;
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
 use ReflectionClass;
 
 /**
@@ -21,19 +22,14 @@ use ReflectionClass;
 class ClassVisitor implements ClassVisitorInterface, UmlComponentInterface
 {
     /**
-     * @var UmlNodeInterface[]
+     * @var RootNamespace
      */
-    protected $nodes = [];
+    protected $rootNamespace;
 
-    /**
-     * @var UmlComponentInterface[]
-     */
-    protected $arrows = [];
-
-    /**
-     * @var string[]
-     */
-    protected $namespaces = [];
+    public function __construct()
+    {
+        $this->rootNamespace = new RootNamespace();
+    }
 
     public function visitClass($className)
     {
@@ -69,8 +65,11 @@ class ClassVisitor implements ClassVisitorInterface, UmlComponentInterface
         } else {
             $node = new Class_($class->getName(), $class->isAbstract(), $class->isFinal());
         }
+
         $this->nodes[$class->getName()] = $node;
-        $this->visitNamespace($class->getNamespaceName());
+
+        $namespace = $this->rootNamespace->getNamespace($class->getNamespaceName());
+        $namespace->addNode($node);
 
         $parentClass = $class->getParentClass();
         $traitNames = $class->getTraitNames();
@@ -90,59 +89,25 @@ class ClassVisitor implements ClassVisitorInterface, UmlComponentInterface
         if ($parentClass) {
             $traitNames = array_diff($traitNames, $parentClass->getTraitNames());
             $interfaceNames = array_diff($interfaceNames, $parentClass->getInterfaceNames());
-            $this->visitRelations($node, [$parentClass->getName()], 'Irstea\PlantUmlBundle\Model\Arrow\ExtendsClass');
+            $this->visitRelations($node, $namespace, [$parentClass->getName()], 'Irstea\PlantUmlBundle\Model\Arrow\ExtendsClass');
         }
 
-        $this->visitRelations($node, $interfaceNames, 'Irstea\PlantUmlBundle\Model\Arrow\ImplementsInterface');
-        $this->visitRelations($node, $traitNames, 'Irstea\PlantUmlBundle\Model\Arrow\UsesTrait');
+        $this->visitRelations($node, $namespace, $interfaceNames, 'Irstea\PlantUmlBundle\Model\Arrow\ImplementsInterface');
+        $this->visitRelations($node, $namespace, $traitNames, 'Irstea\PlantUmlBundle\Model\Arrow\UsesTrait');
 
         return $node;
     }
 
-    protected function visitRelations(UmlNodeInterface $source, array $classNames, $relationClass)
+    protected function visitRelations(UmlNodeInterface $source, NamespaceInterface $namespace, array $classNames, $relationClass)
     {
         foreach ($classNames as $className) {
             $target = $this->visitClass($className);
-            $this->arrows[] = new $relationClass($source, $target);
+            $namespace->addArrow(new $relationClass($source, $target));
         }
     }
 
-    protected function visitNamespace($namespaceName)
+    public function outputTo(WriterInterface $writer)
     {
-        $current =& $this->namespaces;
-        foreach(explode('\\', $namespaceName) as $part) {
-            if (!isset($current[$part])) {
-                $current[$part] = [];
-            }
-            $current = &$current[$part];
-        }
-    }
-
-    public function outputTo($stream)
-    {
-        $this->outputNamespacesTo($stream, $this->namespaces);
-
-        usort($this->nodes, 'Irstea\PlantUmlBundle\Model\Node\BaseNode::compare');
-        foreach ($this->nodes as $node) {
-            $node->outputTo($stream);
-        }
-
-        foreach ($this->arrows as $arrow) {
-            $arrow->outputTo($stream);
-        }
-    }
-
-    protected function outputNamespacesTo($stream, $namespaces)
-    {
-        foreach($namespaces as $name => $children) {
-            fputs($stream, "namespace ");
-            /*while(count($children) == 1) {
-                fputs($stream, $name.'.');
-                list($name, $children) = each($children);
-            }*/
-            fputs($stream, "$name {\n");
-            $this->outputNamespacesTo($stream, $children);
-            fputs($stream, "}\n");
-        }
+        return $this->rootNamespace->outputTo($writer);
     }
 }
diff --git a/Model/NamespaceInterface.php b/Model/NamespaceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1a1e01a96172eecc0d616aeda7d5e16971f690ff
--- /dev/null
+++ b/Model/NamespaceInterface.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model;
+
+/**
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+interface NamespaceInterface
+{
+    /**
+     * @param string $namespaceName
+     * @return NamespaceInterface
+     */
+    public function getNamespace($namespaceName);
+
+    /**
+     * @param UmlNodeInterface $node
+     * @return self
+     */
+    public function addNode(UmlNodeInterface $node);
+
+    /**
+     * @param UmlArrowInterface $arrow
+     * @return self
+     */
+    public function addArrow(UmlArrowInterface $arrow);
+}
diff --git a/Model/Namespace_.php b/Model/Namespace_.php
new file mode 100644
index 0000000000000000000000000000000000000000..09d4f326ec8d5467a203ae612aea2dcc55ec1046
--- /dev/null
+++ b/Model/Namespace_.php
@@ -0,0 +1,68 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model;
+
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
+
+/**
+ * Description of Namespace
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class Namespace_ extends AbstractNamespace
+{
+    /**
+     * @var NamespaceInterface
+     */
+    private $parent;
+
+    /**
+     * @var string
+     */
+    private $name;
+
+    public function __construct(NamespaceInterface $parent, $name)
+    {
+        $this->parent = $parent;
+        $this->name = $name;
+    }
+
+        /**
+     * @param UmlArrowInterface $arrow
+     * @return self
+     */
+    public function addArrow(UmlArrowInterface $arrow)
+    {
+        $this->parent->addArrow($arrow);
+        return $this;
+    }
+
+    /**
+     * @param resource WriterInterface $writer
+     * @return self
+     */
+    public function outputTo(WriterInterface $writer)
+    {
+        if ($this->isEmpty()) {
+            return;
+        }
+
+        $writer
+            ->printf("namespace %s {\n", $this->name)
+            ->indent();
+        $this
+            ->outputNodesTo($writer)
+            ->outputChildrenTo($writer);
+        $writer
+            ->dedent()
+            ->write("}\n");
+
+        return $this;
+    }
+}
diff --git a/Model/Node/BaseNode.php b/Model/Node/BaseNode.php
index 6ad1d0c62b30355cb604f27ed97145899491592e..5c766dc54baf7848170b43c17d9fdbcb24f6ee7a 100644
--- a/Model/Node/BaseNode.php
+++ b/Model/Node/BaseNode.php
@@ -9,6 +9,7 @@
 namespace Irstea\PlantUmlBundle\Model\Node;
 
 use Irstea\PlantUmlBundle\Model\UmlNodeInterface;
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
 
 /**
  * Description of Class
@@ -22,6 +23,11 @@ class BaseNode implements UmlNodeInterface
      */
     private $name;
 
+    /**
+     * @var string
+     */
+    private $alias;
+
     /**
      * @var string
      */
@@ -50,57 +56,72 @@ class BaseNode implements UmlNodeInterface
      */
     function __construct($name, $nodeType, array $classifiers = [], array $stereotypes = [], $ordering = 0)
     {
-        $this->name        = $name;
+        $pos = strrpos($name, '\\');
+        $this->name        = substr($name, $pos + 1);
+        $this->alias       = str_replace('\\', '.', $name)."_node";
+
         $this->nodeType    = $nodeType;
         $this->classifiers = $classifiers;
         $this->stereotypes = $stereotypes;
         $this->ordering    = $ordering;
     }
 
-    public function outputTo($stream)
+    public function outputTo(WriterInterface $writer)
     {
-        $this->outputClassifiersTo($stream);
-        $this->outputNodeTypeTo($stream);
-        $this->outputAliasTo($stream);
-        $this->outputStereotypesTo($stream);
-        fputs($stream, " {\n");
-        $this->outputAttributesTo($stream);
-        $this->outputMethodsTo($stream);
-        fputs($stream, "}\n");
+        $this
+            ->outputClassifiersTo($writer)
+            ->outputNodeTypeTo($writer);
+        $writer->printf('"%s" as %s', $this->name, $this->alias);
+        $this
+            ->outputStereotypesTo($writer);
+        $writer
+            ->write(" {\n")
+            ->indent();
+        $this
+            ->outputAttributesTo($writer)
+            ->outputMethodsTo($writer);
+        $writer
+            ->dedent()
+            ->write("}\n");
+        return $this;
     }
 
-    public function outputAliasTo($stream)
+    public function outputAliasTo(WriterInterface $writer)
     {
-        fputs($stream, '"'.str_replace('\\', '.', $this->name).'"');
+        $writer->write($this->alias);
+        return $this;
     }
 
-    protected function outputClassifiersTo($stream)
+    protected function outputClassifiersTo(WriterInterface $writer)
     {
         foreach($this->classifiers as $classifier) {
-            fputs($stream, "$classifier ");
+            $writer->printf('%s ', $classifier);
         }
+        return $this;
     }
 
-    protected function outputNodeTypeTo($stream)
+    protected function outputNodeTypeTo(WriterInterface $writer)
     {
-        fputs($stream, $this->nodeType." ");
+        $writer->printf('%s ', $this->nodeType);
+        return $this;
     }
 
-    protected function outputStereotypesTo($stream)
+    protected function outputStereotypesTo(WriterInterface $writer)
     {
-        foreach($this->stereotypes as $stereotypes) {
-            fputs($stream, " <<$stereotypes>>");
+        foreach($this->stereotypes as $stereotype) {
+            $writer->printf(' <<%s>>', $stereotype);
         }
+        return $this;
     }
 
-    protected function outputAttributesTo($stream)
+    protected function outputAttributesTo(WriterInterface $writer)
     {
-        // NOP
+        return $this;
     }
 
-    protected function outputMethodsTo($stream)
+    protected function outputMethodsTo(WriterInterface $writer)
     {
-        // NOP
+        return $this;
     }
 
     static public function compare(BaseNode $a, BaseNode $b)
diff --git a/Model/Orm/EntityVisitor.php b/Model/Orm/EntityVisitor.php
index 74786379d83ad55bdf43bc254b6fdb184ba29d64..9830995a04d1067ae39bd56550a4bc53dfa496e1 100644
--- a/Model/Orm/EntityVisitor.php
+++ b/Model/Orm/EntityVisitor.php
@@ -25,6 +25,8 @@ class EntityVisitor extends ClassVisitor
 
     public function __construct(array $metadata)
     {
+        parent::__construct();
+
         foreach($metadata as $md) {
             /* @var $md ClassMetadata */
             $this->metadata[$md->getReflectionClass()->getName()] = $md;
diff --git a/Model/RootNamespace.php b/Model/RootNamespace.php
new file mode 100644
index 0000000000000000000000000000000000000000..968af9d5a70190aea6a18016841e3950f17617b9
--- /dev/null
+++ b/Model/RootNamespace.php
@@ -0,0 +1,45 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model;
+
+/**
+ * Description of RootNamespace
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class RootNamespace extends AbstractNamespace
+{
+    /**
+     * @var UmlArrowInterface[]
+     */
+    private $arrows = [];
+
+    public function addArrow(UmlArrowInterface $arrow)
+    {
+        $this->arrows[] = $arrow;
+        return $this;
+    }
+
+    public function outputTo(\Irstea\PlantUmlBundle\Writer\WriterInterface $writer)
+    {
+        $this
+            ->outputNodesTo($writer)
+            ->outputChildrenTo($writer)
+            ->outputArrowsTo($writer);
+        return $this;
+    }
+
+    protected function outputArrowsTo(\Irstea\PlantUmlBundle\Writer\WriterInterface $writer)
+    {
+        foreach ($this->arrows as $arrow) {
+            $arrow->outputTo($writer);
+        }
+        return $this;
+    }
+}
diff --git a/Model/UmlArrowInterface.php b/Model/UmlArrowInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..9bc1d028c59a7f33f6931b95d13ae12123552150
--- /dev/null
+++ b/Model/UmlArrowInterface.php
@@ -0,0 +1,17 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Model;
+
+/**
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+interface UmlArrowInterface extends UmlComponentInterface
+{
+}
diff --git a/Model/UmlComponentInterface.php b/Model/UmlComponentInterface.php
index 65b13c7c9a726f136343582ff99f523a4fd4d4a2..1089443982dde26122946cccb16788823e326eb9 100644
--- a/Model/UmlComponentInterface.php
+++ b/Model/UmlComponentInterface.php
@@ -8,11 +8,16 @@
 
 namespace Irstea\PlantUmlBundle\Model;
 
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
+
 /**
  *
  * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
  */
 interface UmlComponentInterface
 {
-    public function outputTo($stream);
+    /**
+     * @param WriterInterface $writer
+     */
+    public function outputTo(WriterInterface $writer);
 }
diff --git a/Model/UmlNodeInterface.php b/Model/UmlNodeInterface.php
index 2594948c2e1b514c08c20a6cc57f7c31ea0baceb..8ffed94865aa08de34c27ebe517b703d9e518fa7 100644
--- a/Model/UmlNodeInterface.php
+++ b/Model/UmlNodeInterface.php
@@ -8,11 +8,16 @@
 
 namespace Irstea\PlantUmlBundle\Model;
 
+use Irstea\PlantUmlBundle\Writer\WriterInterface;
+
 /**
  *
  * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
  */
-interface UmlNodeInterface extends \Irstea\PlantUmlBundle\Model\UmlComponentInterface
+interface UmlNodeInterface extends UmlComponentInterface
 {
-    public function outputAliasTo($stream);
+    /**
+     * @param WriterInterface $writer
+     */
+    public function outputAliasTo(WriterInterface $writer);
 }
diff --git a/Writer/AbstractWriter.php b/Writer/AbstractWriter.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a14d3a2f40401feb7ba39506b1a8f556e41771a
--- /dev/null
+++ b/Writer/AbstractWriter.php
@@ -0,0 +1,66 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Writer;
+
+/**
+ * Description of AbstractWriter
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+abstract class AbstractWriter implements WriterInterface
+{
+    /**
+     * @var int
+     */
+    private $indentation = 0;
+
+    /**
+     * @var string
+     */
+    private $buffer;
+
+    public function dedent($n = 1)
+    {
+        $this->indentation = max(0, $this->indentation - $n);
+        return $this;
+    }
+
+    public function indent($n = 1)
+    {
+        $this->indentation += $n;
+        return $this;
+    }
+
+    public function printf($format)
+    {
+        $args = func_get_args();
+        array_shift($args);
+        $this->write(vsprintf($format, $args));
+        return $this;
+    }
+
+    public function write($data)
+    {
+        $buffer = $this->buffer . $data;
+        $indentation = str_repeat("  ", $this->indentation);
+        $current = 0;
+        while($current < strlen($buffer) && false !== ($next = strpos($buffer, "\n", $current))) {
+            $next++;
+            $this->doWrite($indentation . substr($buffer, $current, $next - $current));
+            $current = $next;
+        }
+        $this->buffer = substr($buffer, $current);
+        return $this;
+    }
+
+    /**
+     * @param string $data
+     */
+    abstract protected function doWrite($data);
+}
diff --git a/Writer/OutputWriter.php b/Writer/OutputWriter.php
new file mode 100644
index 0000000000000000000000000000000000000000..c43fb7fe997ffd98b5a266f2271f0533975e145d
--- /dev/null
+++ b/Writer/OutputWriter.php
@@ -0,0 +1,34 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Writer;
+
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Description of OutputWriter
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+class OutputWriter extends AbstractWriter
+{
+    /**
+     * @var OutputInterface
+     */
+    private $output;
+
+    public function __construct(OutputInterface $output)
+    {
+        $this->output = $output;
+    }
+
+    protected function doWrite($data)
+    {
+        $this->output->write($data);
+    }
+}
diff --git a/Writer/WriterInterface.php b/Writer/WriterInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..06036fa3c2175b09cf07de21033e01ce5c5281da
--- /dev/null
+++ b/Writer/WriterInterface.php
@@ -0,0 +1,41 @@
+<?php
+
+/*
+ * © 2016 IRSTEA
+ * Guillaume Perréal <guillaume.perreal@irstea.fr>
+ * Tous droits réservés.
+ */
+
+namespace Irstea\PlantUmlBundle\Writer;
+
+/**
+ *
+ * @author Guillaume Perréal <guillaume.perreal@irstea.fr>
+ */
+interface WriterInterface
+{
+    /**
+     * @param int $n
+     * @return self
+     */
+    public function indent($n = 1);
+
+    /**
+     * @param int $n
+     * @return self
+     */
+    public function dedent($n = 1);
+
+    /**
+     * @param string $data
+     * @return self
+     */
+    public function write($data);
+
+    /**
+     * @param string $fmt
+     * @param mixed ...
+     * @return self
+     */
+    public function printf($fmt);
+}