---
type: "article"
title: "Principios SOLID"
summary: "<p>A pesar de que existe mucho material escrito sobre este tema, en mi día a día me encuentro con software diseñado desde cero sin tener en cuenta algunos o ninguno de los principios SOLID.</p>\n<p>Los principios SOLID son la base para diseñar software que sea flexible, testeable y fácil de mantener.</p>\n<p>Algunos están ya bastante asumidos por la comunidad de desarrollo, otros no tanto.</p>\n<p>En este artículo explicaré cada uno de estos principios con simples ejemplos que representan escenarios típicos de nuestro día a día.</p>\n<h3 id=\"single-responsability\">Single responsability</h3>\n<p>Una clase debería tener una única responsabilidad.</p>\n<p>Este principio quizás sea aparentemente el más sencillo de entender. Aun así, son frecuentes las implementaciones que se lo saltan, incluso de forma intencionada.</p>\n<p>Un ejemplo de implementación que se lo salta es la de Active Record que se implementa en el ORM de RubyOnRails, cuyos modelos suelen ser propensos a atraer responsabilidades ajenas a las que deberían tener.</p>\n<p>Un ejemplo parecido de esto sería este código</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">Message</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">setFrom</span><span class=\"p\">(</span> <span class=\"nx\">Person</span> <span class=\"nv\">$person</span> <span class=\"p\">)</span> <span class=\"p\">{}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">setTo</span><span class=\"p\">(</span> <span class=\"nx\">Person</span> <span class=\"nv\">$person</span> <span class=\"p\">)</span> <span class=\"p\">{}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">send</span><span class=\"p\">()</span> <span class=\"p\">{}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>En este código, vemos que una clase mensaje implementa el método &ldquo;send&rdquo; para enviarse a sí mismo. Sin embargo, esta responsabilidad debería ser delegada en un objeto cuya labor sea enviar.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$user1</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">Person</span><span class=\"p\">(</span> <span class=\"s2\">&#34;Asier&#34;</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$user2</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">Person</span><span class=\"p\">(</span><span class=\"s2\">&#34;Thor&#34;</span><span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">// componemos el mensaje\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$message</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">Message</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$message</span><span class=\"o\">-&gt;</span><span class=\"na\">from</span><span class=\"p\">(</span> <span class=\"nv\">$user1</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$message</span><span class=\"o\">-&gt;</span><span class=\"na\">to</span><span class=\"p\">(</span> <span class=\"nv\">$user2</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">// enviamos el mensaje mediante un Sender\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">SMSSender</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span><span class=\"o\">-&gt;</span><span class=\"na\">send</span><span class=\"p\">(</span> <span class=\"nv\">$message</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">EmailSender</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span><span class=\"o\">-&gt;</span><span class=\"na\">send</span><span class=\"p\">(</span> <span class=\"nv\">$message</span> <span class=\"p\">);</span>\n</span></span></code></pre></div><p>Como vemos en el código anterior, la primera ventaja de separar en responsabilidades nuestro código reside en que podemos tener flexibilidad a la hora de trabajar con nuestros mensajes sin cambiar el código de las clases que los representan.</p>\n<p>En un principio quizás hayamos definido que nuestros mensajes se enviasen por email, pero si quisiéramos enviar por otros medios, deberíamos hacer cambios en nuestra clase Mensaje para poder implementar cambios en este sentido.</p>\n<p>En muchas ocasiones, el aplicar estas modificaciones a las clases para poder mantener responsabilidades que no son las suyas las hacen magnéticas a más responsabilidades.</p>\n<p>Por ejemplo si seguimos la estrategia de mantener responsabilidades en la clase Mensaje, esta podría también ser susceptible de implementar el método &ldquo;save&rdquo;, para guardar el mensaje en base de datos. O el método &ldquo;print&rdquo; para imprimirlo. Sin embargo, el otorgar de estas responsabilidades a la clase Message, conllevaría saltarse este patrón corriendo el peligro de limitar la flexibilidad, propiciar la aparición de código redundante a futuro (por ejemplo: necesidad de implementar métodos &ldquo;save&rdquo; o &ldquo;send&rdquo; en diferentes clases que no tienen ninguna base común entre ellas, utilizando la herencia de forma incorrecta con clases abstractas) y aumentar el coste de mantenimiento de nuestro software.</p>\n<h3 id=\"open-close\">Open-close</h3>\n<p>El principio abierto-cerrado es para mí una de las lecciones más importantes que he aprendido como desarrollador de software.</p>\n<p>El objetivo a conseguir es hacer extensible tu código sin tener que modificarlo.</p>\n<p>Pongamos el siguiente ejemplo que no respeta este principio:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">SenderFactory</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">createFromProtocol</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">switch</span> <span class=\"p\">(</span> <span class=\"nv\">$protocol</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">case</span> <span class=\"s1\">&#39;sms&#39;</span><span class=\"o\">:</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return</span> <span class=\"k\">new</span> <span class=\"nx\">SmsSender</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">case</span> <span class=\"s1\">&#39;email&#39;</span><span class=\"o\">:</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return</span> <span class=\"k\">new</span> <span class=\"nx\">EmailSender</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$factory</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">SenderFactory</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span> <span class=\"o\">=</span> <span class=\"nv\">$factory</span><span class=\"o\">-&gt;</span><span class=\"na\">createFromProtocol</span><span class=\"p\">(</span><span class=\"s1\">&#39;sms&#39;</span><span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span><span class=\"o\">-&gt;</span><span class=\"na\">send</span><span class=\"p\">(</span> <span class=\"nv\">$message</span> <span class=\"p\">);</span>\n</span></span></code></pre></div><p>En esta típica clase de Factoría, tenemos un Switch/Case para crear cada uno de los Sender a los que dará soporte. Si quisiéramos añadir un nuevo tipo de Sender, deberíamos añadir otro case más para el mismo, teniendo que modificar la clase por cada extensión.</p>\n<p>Para conseguir respetar el principio Abierto-Cerrado, deberíamos seguir los siguientes pasos:</p>\n<ol>\n<li>Crear una interfaz para los objeto Sender</li>\n</ol>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\"><span class=\"k\">interface</span> <span class=\"nx\">SenderInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">send</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><ol start=\"2\">\n<li>Crear un sistema para poder añadir de forma externa las diferentes implementaciones de Senders en la factoría. Un ejemplo simplificado (no utilizar en producción):</li>\n</ol>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">SenderFactory</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">private</span> <span class=\"nv\">$_senders</span> <span class=\"o\">=</span> <span class=\"p\">[];</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">createFromProtocol</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if</span><span class=\"p\">(</span> <span class=\"nx\">isset</span> <span class=\"p\">(</span><span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">_senders</span><span class=\"p\">[</span> <span class=\"nv\">$protocol</span> <span class=\"p\">]</span> <span class=\"p\">)</span>  <span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">return</span> <span class=\"k\">new</span> <span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">_senders</span><span class=\"p\">[</span> <span class=\"nv\">$protocol</span> <span class=\"p\">];</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"nx\">thrown</span> <span class=\"k\">new</span> <span class=\"nx\">Exception</span><span class=\"p\">(</span><span class=\"s2\">&#34;there is any sender for &#34;</span> <span class=\"o\">.</span> <span class=\"nv\">$protocol</span><span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">addSender</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span><span class=\"p\">,</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$senderClass</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">_senders</span><span class=\"p\">[</span> <span class=\"nv\">$protocol</span> <span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"nv\">$sender</span><span class=\"p\">;</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>De esta forma podríamos añadir de forma externa sin preocuparnos de tener que tocar el código de la factoría:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$senderFactory</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">SenderFactory</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$senderFactory</span><span class=\"o\">-&gt;</span><span class=\"na\">addSender</span><span class=\"p\">(</span> <span class=\"s1\">&#39;sms&#39;</span><span class=\"p\">,</span> <span class=\"nx\">SmsSender</span><span class=\"o\">::</span><span class=\"na\">class</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$senderFactory</span><span class=\"o\">-&gt;</span><span class=\"na\">addSender</span><span class=\"p\">(</span> <span class=\"s1\">&#39;email&#39;</span><span class=\"p\">,</span> <span class=\"nx\">EmailSender</span><span class=\"o\">::</span><span class=\"na\">class</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span> <span class=\"o\">=</span> <span class=\"nv\">$senderFactory</span><span class=\"o\">-&gt;</span><span class=\"na\">createFromProtocol</span><span class=\"p\">(</span> <span class=\"s1\">&#39;sms&#39;</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$sender</span><span class=\"o\">-&gt;</span><span class=\"na\">send</span><span class=\"p\">(</span> <span class=\"nv\">$message</span> <span class=\"p\">);</span>\n</span></span></code></pre></div><h3 id=\"liscov-sustitution\">Liscov sustitution</h3>\n<!-- raw HTML omitted -->\n<p>Bárbara Liskov<!-- raw HTML omitted --></p>\n<p>El principio de sustitución de Liscov es uno de los que más frecuentemente se suelen saltar.</p>\n<p>Básicamente lo que dicta es que si una clase hereda de otra, el funcionamiento de la aplicación no debería verse afectado si esta es sustituida por su clase padre.</p>\n<p>Esto también relativo a las interfaces. Si una clase que implementa una interfaz es sustituida por otra que implementa esa interfaz, el comportamiento no debería verse afectado.</p>\n<p>Esto conlleva varias cosas:</p>\n<ul>\n<li>Los métodos públicos de la clase hija y padre deberían ser exactamente los mismos</li>\n<li>Los métodos deberían devolver los mismos tipos de datos</li>\n<li>Lo que se exprese en un método abstracto o no, en la clase padre o la interfaz, debería ser lo que este método realice, sin sorpresas extrañas.</li>\n</ul>\n<p>Un ejemplo sobre este último punto: si tenemos esta interfaz</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">interface</span> <span class=\"nx\">SenderFactoryInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">createFromProtocol</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">addSender</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span><span class=\"p\">,</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"nx\">SenderInterface</span> <span class=\"nv\">$sender</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>Esperamos que las clases que implementen la SenderFactoryInterface puedan crear un Sender que hayamos cargado en la misma.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">SenderFactory</span> <span class=\"k\">implements</span> <span class=\"nx\">SenderFactoryInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">createFromProtocol</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">if</span> <span class=\"p\">(</span> <span class=\"o\">!</span><span class=\"nv\">$this</span><span class=\"o\">-&gt;</span><span class=\"na\">checkIfMeetsSomeCondition</span><span class=\"p\">(</span> <span class=\"nv\">$protocol</span> <span class=\"p\">)</span> <span class=\"p\">)</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"nx\">thrown</span> <span class=\"k\">new</span> <span class=\"nx\">Exception</span> <span class=\"p\">(</span> <span class=\"s1\">&#39;Protocol not supported&#39;</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"o\">....</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>En este ejemplo vemos que hay una condición interna en el método createFromProtocol que decide si funcionar o no con un tipo de protocolo. Esto viola el principio de sustitución de Liscov ya que otra clase que implemente SenderFactoryInterface no tiene por qué contemplar esa condición y esto puede derivar en inestabilidad del sistema al cambiar de SenderFactory.</p>\n<p>La idea como conclusión es que debe respetarse lo que define una interfaz o una clase padre, sin añadir ni exponer funcionalidad adicional que esté fuera esa definición.</p>\n<h3 id=\"interface-segregation\">Interface segregation</h3>\n<!-- raw HTML omitted -->\n<p>Robert Martin<!-- raw HTML omitted --></p>\n<p>Al seguir el principio de Segregación de interfaces debemos asegurarnos de que una dependencia que inyectemos en una clase no muestre métodos que no se necesiten o no tengan sentido para lo que pretendemos hacer.</p>\n<p>Por ejemplo, si tenemos una interfaz que define cómo podemos extraer y guardar datos de un sistema de almacenamiento:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">interface</span> <span class=\"nx\">StorageManagerInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">getItems</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">save</span><span class=\"p\">(</span> <span class=\"nx\">EntityInterface</span> <span class=\"nv\">$item</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>Y tenemos una clase que necesite leer datos de ese sistema para imprimirlos:</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">PrintService</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">printLines</span><span class=\"p\">(</span> <span class=\"nx\">StorageManagerInterface</span> <span class=\"nv\">$storage</span> <span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>Dentro del método printLines no nos interesa guardar nada en el sistema de almacenamiento. De hecho, sería peligroso hacerlo en ese método, ya que se supone que no vamos a hacer ninguna manipulación, sólo deberíamos imprimir los datos que nos traigamos del sistema de almacenamiento.</p>\n<p>Para no saltarnos el principio de Segregación de interfaces, deberíamos separar las operaciones de lectura y escritura en dos interfaces distintas. Si por alguna razón necesitásemos ambas operaciones en alguna clase, podríamos tener otra interfaz que implemente dichas interfaces.</p>\n<p>Nuestro PrintService ahora ya tiene únicamente los métodos que necesita como vemos en el siguiente ejemplo.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">interface</span> <span class=\"nx\">StorageReaderInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">getItems</span><span class=\"p\">();</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">interface</span> <span class=\"nx\">StorageeWriterInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">save</span><span class=\"p\">(</span> <span class=\"nx\">EntityInterface</span> <span class=\"nv\">$entity</span> <span class=\"p\">);</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">interface</span> <span class=\"nx\">StorageManagerInterface</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">implements</span> <span class=\"nx\">StorageReaderInterface</span><span class=\"p\">,</span> <span class=\"nx\">StorageWriterInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">PrintService</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"nf\">printLines</span><span class=\"p\">(</span> <span class=\"nx\">StorageReaderInterface</span> <span class=\"nv\">$storage</span> <span class=\"p\">)</span> <span class=\"p\">{</span> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><h3 id=\"dependency-inversion\">Dependency inversion</h3>\n<p>La idea de la inversión de dependencias es que nuestro código dependa siempre de abstracciones, no de clases concretas.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">// incorrecto\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">NotificationService</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"fm\">__construct</span><span class=\"p\">(</span> <span class=\"nx\">EmailSender</span> <span class=\"nv\">$sender</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"o\">...</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"c1\">// correcto\n</span></span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">NotificationService</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"fm\">__construct</span><span class=\"p\">(</span> <span class=\"nx\">SenderInterface</span> <span class=\"nv\">$sender</span> <span class=\"p\">)</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"o\">...</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>En el ejemplo superior vemos cómo respetar este principio y que al inyectar la interfaz SenderInterface, le damos más flexibilidad pudiendo cambiar en un futuro el tipo de Sender sin tener que modificar el código.</p>\n<p>Sin embargo, pasar una interfaz no es lo único recomendable. Suele ser habitual que utilicemos interfaces de un framework que utilicemos para desarrollar nuestro código.</p>\n<p>Esto nos genera una dependencia con el framework, lo cual puede ser un problema si luego queremos reutilizar código separándolo en un paquete independiente.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">LoggerService</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"fm\">__construct</span><span class=\"p\">(</span> <span class=\"nx\">Framework\\EventDispatcherInterface</span> <span class=\"nv\">$dispatcher</span> <span class=\"p\">)</span> <span class=\"p\">{}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span></code></pre></div><p>Lo ideal sería crear nuestra propia interfaz e implementarla en una clase que haga uso de la interfaz que nos provee el framework. Esto nos permite cambiar en un futuro de framework sin que nuestro código se vea afectado.</p>\n<div class=\"highlight\"><pre tabindex=\"0\" class=\"chroma\"><code class=\"language-php\" data-lang=\"php\"><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">FrameworkEventDispatcher</span>\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">implements</span> <span class=\"nx\">EventDispatcherInterface</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"fm\">__construct</span><span class=\"p\">(</span><span class=\"nx\">Framework\\EventDispatcherInterface</span> <span class=\"nv\">$dispatcher</span><span class=\"p\">)</span> <span class=\"p\">{}</span>\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"k\">class</span> <span class=\"nc\">LoggerService</span> <span class=\"p\">{</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"> <span class=\"k\">public</span> <span class=\"k\">function</span> <span class=\"fm\">__construct</span><span class=\"p\">(</span> <span class=\"nx\">EventDispatcherInterface</span> <span class=\"nv\">$dispatcher</span> <span class=\"p\">)</span> <span class=\"p\">{}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"p\">}</span>\n</span></span><span class=\"line\"><span class=\"cl\">\n</span></span><span class=\"line\"><span class=\"cl\"><span class=\"nv\">$logger</span> <span class=\"o\">=</span> <span class=\"k\">new</span> <span class=\"nx\">LoggerService</span><span class=\"p\">(</span> <span class=\"k\">new</span> <span class=\"nx\">FrameworkEventDispatcher</span><span class=\"p\">()</span> <span class=\"p\">);</span>\n</span></span></code></pre></div><h3 id=\"conclusión\">Conclusión</h3>\n<p>Los principios SOLID nos permiten diseñar nuestro software para que después de evolucionarlo y mantenerlo durante años no se convierta en una mala partida de Tetris.</p>\n<p>Si tenemos la mente abierta incluso podemos aplicarlos fuera del código o incluso del mundo del software, en otras disciplinas y artes creativas.</p>"
newsletter: "Asier Marqués, blog personal"
newsletter_handle: "blog-asiermarques-com"
newsletter_url: "https://usecommune.com/n/blog-asiermarques-com"
author: "Asier Marqués (@asier)"
published: "2018-04-29T15:49:13.000Z"
canonical_url: "https://usecommune.com/n/blog-asiermarques-com/a/principios-solid"
markdown_url: "https://usecommune.com/n/blog-asiermarques-com/a/principios-solid.md"
chat_url: "https://usecommune.com/n/blog-asiermarques-com/a/principios-solid/chat"
source_url: "https://blog.asiermarques.com/2018/principios-solid/"
body_source: "imported"
likes: 0
replies: 0
body_words: 2550
---

# Principios SOLID

\<p>A pesar de que existe mucho material escrito sobre este tema, en mi día a día me encuentro con software diseñado desde cero sin tener en cuenta algunos o ninguno de los principios SOLID.\</p> \<p>Los principios SOLID son la base para diseñar software que sea flexible, testeable y fácil de mantener.\</p> \<p>Algunos están ya bastante asumidos por la comunidad de desarrollo, otros no tanto.\</p> \<p>En este artículo explicaré cada uno de estos principios con simples ejemplos que representan escenarios típicos de nuestro día a día.\</p> \<h3 id="single-responsability">Single responsability\</h3> \<p>Una clase debería tener una única responsabilidad.\</p> \<p>Este principio quizás sea aparentemente el más sencillo de entender. Aun así, son frecuentes las implementaciones que se lo saltan, incluso de forma intencionada.\</p> \<p>Un ejemplo de implementación que se lo salta es la de Active Record que se implementa en el ORM de RubyOnRails, cuyos modelos suelen ser propensos a atraer responsabilidades ajenas a las que deberían tener.\</p> \<p>Un ejemplo parecido de esto sería este código\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">Message\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">setFrom\</span>\<span class="p">(\</span> \<span class="nx">Person\</span> \<span class="nv">$person\</span> \<span class="p">)\</span> \<span class="p">{}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">setTo\</span>\<span class="p">(\</span> \<span class="nx">Person\</span> \<span class="nv">$person\</span> \<span class="p">)\</span> \<span class="p">{}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">send\</span>\<span class="p">()\</span> \<span class="p">{}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>En este código, vemos que una clase mensaje implementa el método &ldquo;send&rdquo; para enviarse a sí mismo. Sin embargo, esta responsabilidad debería ser delegada en un objeto cuya labor sea enviar.\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$user1\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">Person\</span>\<span class="p">(\</span> \<span class="s2">&#34;Asier&#34;\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$user2\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">Person\</span>\<span class="p">(\</span>\<span class="s2">&#34;Thor&#34;\</span>\<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="c1">// componemos el mensaje \</span>\</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$message\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">Message\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$message\</span>\<span class="o">-&gt;\</span>\<span class="na">from\</span>\<span class="p">(\</span> \<span class="nv">$user1\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$message\</span>\<span class="o">-&gt;\</span>\<span class="na">to\</span>\<span class="p">(\</span> \<span class="nv">$user2\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="c1">// enviamos el mensaje mediante un Sender \</span>\</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">SMSSender\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span>\<span class="o">-&gt;\</span>\<span class="na">send\</span>\<span class="p">(\</span> \<span class="nv">$message\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">EmailSender\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span>\<span class="o">-&gt;\</span>\<span class="na">send\</span>\<span class="p">(\</span> \<span class="nv">$message\</span> \<span class="p">);\</span> \</span>\</span>\</code>\</pre>\</div>\<p>Como vemos en el código anterior, la primera ventaja de separar en responsabilidades nuestro código reside en que podemos tener flexibilidad a la hora de trabajar con nuestros mensajes sin cambiar el código de las clases que los representan.\</p> \<p>En un principio quizás hayamos definido que nuestros mensajes se enviasen por email, pero si quisiéramos enviar por otros medios, deberíamos hacer cambios en nuestra clase Mensaje para poder implementar cambios en este sentido.\</p> \<p>En muchas ocasiones, el aplicar estas modificaciones a las clases para poder mantener responsabilidades que no son las suyas las hacen magnéticas a más responsabilidades.\</p> \<p>Por ejemplo si seguimos la estrategia de mantener responsabilidades en la clase Mensaje, esta podría también ser susceptible de implementar el método &ldquo;save&rdquo;, para guardar el mensaje en base de datos. O el método &ldquo;print&rdquo; para imprimirlo. Sin embargo, el otorgar de estas responsabilidades a la clase Message, conllevaría saltarse este patrón corriendo el peligro de limitar la flexibilidad, propiciar la aparición de código redundante a futuro (por ejemplo: necesidad de implementar métodos &ldquo;save&rdquo; o &ldquo;send&rdquo; en diferentes clases que no tienen ninguna base común entre ellas, utilizando la herencia de forma incorrecta con clases abstractas) y aumentar el coste de mantenimiento de nuestro software.\</p> \<h3 id="open-close">Open-close\</h3> \<p>El principio abierto-cerrado es para mí una de las lecciones más importantes que he aprendido como desarrollador de software.\</p> \<p>El objetivo a conseguir es hacer extensible tu código sin tener que modificarlo.\</p> \<p>Pongamos el siguiente ejemplo que no respeta este principio:\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">SenderFactory\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">createFromProtocol\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">switch\</span> \<span class="p">(\</span> \<span class="nv">$protocol\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">case\</span> \<span class="s1">&#39;sms&#39;\</span>\<span class="o">:\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">return\</span> \<span class="k">new\</span> \<span class="nx">SmsSender\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">case\</span> \<span class="s1">&#39;email&#39;\</span>\<span class="o">:\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">return\</span> \<span class="k">new\</span> \<span class="nx">EmailSender\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$factory\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">SenderFactory\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span> \<span class="o">=\</span> \<span class="nv">$factory\</span>\<span class="o">-&gt;\</span>\<span class="na">createFromProtocol\</span>\<span class="p">(\</span>\<span class="s1">&#39;sms&#39;\</span>\<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span>\<span class="o">-&gt;\</span>\<span class="na">send\</span>\<span class="p">(\</span> \<span class="nv">$message\</span> \<span class="p">);\</span> \</span>\</span>\</code>\</pre>\</div>\<p>En esta típica clase de Factoría, tenemos un Switch/Case para crear cada uno de los Sender a los que dará soporte. Si quisiéramos añadir un nuevo tipo de Sender, deberíamos añadir otro case más para el mismo, teniendo que modificar la clase por cada extensión.\</p> \<p>Para conseguir respetar el principio Abierto-Cerrado, deberíamos seguir los siguientes pasos:\</p> \<ol> \<li>Crear una interfaz para los objeto Sender\</li> \</ol> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl">\<span class="k">interface\</span> \<span class="nx">SenderInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">send\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<ol start="2"> \<li>Crear un sistema para poder añadir de forma externa las diferentes implementaciones de Senders en la factoría. Un ejemplo simplificado (no utilizar en producción):\</li> \</ol> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">SenderFactory\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">private\</span> \<span class="nv">$\_senders\</span> \<span class="o">=\</span> \<span class="p">\[\];\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">createFromProtocol\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">if\</span>\<span class="p">(\</span> \<span class="nx">isset\</span> \<span class="p">(\</span>\<span class="nv">$this\</span>\<span class="o">-&gt;\</span>\<span class="na">\_senders\</span>\<span class="p">\[\</span> \<span class="nv">$protocol\</span> \<span class="p">\]\</span> \<span class="p">)\</span> \<span class="p">)\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">return\</span> \<span class="k">new\</span> \<span class="nv">$this\</span>\<span class="o">-&gt;\</span>\<span class="na">\_senders\</span>\<span class="p">\[\</span> \<span class="nv">$protocol\</span> \<span class="p">\];\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="nx">thrown\</span> \<span class="k">new\</span> \<span class="nx">Exception\</span>\<span class="p">(\</span>\<span class="s2">&#34;there is any sender for &#34;\</span> \<span class="o">.\</span> \<span class="nv">$protocol\</span>\<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">addSender\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span>\<span class="p">,\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="nv">$senderClass\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="nv">$this\</span>\<span class="o">-&gt;\</span>\<span class="na">\_senders\</span>\<span class="p">\[\</span> \<span class="nv">$protocol\</span> \<span class="p">\]\</span> \<span class="o">=\</span> \<span class="nv">$sender\</span>\<span class="p">;\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>De esta forma podríamos añadir de forma externa sin preocuparnos de tener que tocar el código de la factoría:\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$senderFactory\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">SenderFactory\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$senderFactory\</span>\<span class="o">-&gt;\</span>\<span class="na">addSender\</span>\<span class="p">(\</span> \<span class="s1">&#39;sms&#39;\</span>\<span class="p">,\</span> \<span class="nx">SmsSender\</span>\<span class="o">::\</span>\<span class="na">class\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$senderFactory\</span>\<span class="o">-&gt;\</span>\<span class="na">addSender\</span>\<span class="p">(\</span> \<span class="s1">&#39;email&#39;\</span>\<span class="p">,\</span> \<span class="nx">EmailSender\</span>\<span class="o">::\</span>\<span class="na">class\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span> \<span class="o">=\</span> \<span class="nv">$senderFactory\</span>\<span class="o">-&gt;\</span>\<span class="na">createFromProtocol\</span>\<span class="p">(\</span> \<span class="s1">&#39;sms&#39;\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$sender\</span>\<span class="o">-&gt;\</span>\<span class="na">send\</span>\<span class="p">(\</span> \<span class="nv">$message\</span> \<span class="p">);\</span> \</span>\</span>\</code>\</pre>\</div>\<h3 id="liscov-sustitution">Liscov sustitution\</h3> \<!-- raw HTML omitted --> \<p>Bárbara Liskov\<!-- raw HTML omitted -->\</p> \<p>El principio de sustitución de Liscov es uno de los que más frecuentemente se suelen saltar.\</p> \<p>Básicamente lo que dicta es que si una clase hereda de otra, el funcionamiento de la aplicación no debería verse afectado si esta es sustituida por su clase padre.\</p> \<p>Esto también relativo a las interfaces. Si una clase que implementa una interfaz es sustituida por otra que implementa esa interfaz, el comportamiento no debería verse afectado.\</p> \<p>Esto conlleva varias cosas:\</p> \<ul> \<li>Los métodos públicos de la clase hija y padre deberían ser exactamente los mismos\</li> \<li>Los métodos deberían devolver los mismos tipos de datos\</li> \<li>Lo que se exprese en un método abstracto o no, en la clase padre o la interfaz, debería ser lo que este método realice, sin sorpresas extrañas.\</li> \</ul> \<p>Un ejemplo sobre este último punto: si tenemos esta interfaz\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">interface\</span> \<span class="nx">SenderFactoryInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">createFromProtocol\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">addSender\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span>\<span class="p">,\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="nx">SenderInterface\</span> \<span class="nv">$sender\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>Esperamos que las clases que implementen la SenderFactoryInterface puedan crear un Sender que hayamos cargado en la misma.\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">SenderFactory\</span> \<span class="k">implements\</span> \<span class="nx">SenderFactoryInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">createFromProtocol\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">if\</span> \<span class="p">(\</span> \<span class="o">!\</span>\<span class="nv">$this\</span>\<span class="o">-&gt;\</span>\<span class="na">checkIfMeetsSomeCondition\</span>\<span class="p">(\</span> \<span class="nv">$protocol\</span> \<span class="p">)\</span> \<span class="p">)\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="nx">thrown\</span> \<span class="k">new\</span> \<span class="nx">Exception\</span> \<span class="p">(\</span> \<span class="s1">&#39;Protocol not supported&#39;\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="o">....\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>En este ejemplo vemos que hay una condición interna en el método createFromProtocol que decide si funcionar o no con un tipo de protocolo. Esto viola el principio de sustitución de Liscov ya que otra clase que implemente SenderFactoryInterface no tiene por qué contemplar esa condición y esto puede derivar en inestabilidad del sistema al cambiar de SenderFactory.\</p> \<p>La idea como conclusión es que debe respetarse lo que define una interfaz o una clase padre, sin añadir ni exponer funcionalidad adicional que esté fuera esa definición.\</p> \<h3 id="interface-segregation">Interface segregation\</h3> \<!-- raw HTML omitted --> \<p>Robert Martin\<!-- raw HTML omitted -->\</p> \<p>Al seguir el principio de Segregación de interfaces debemos asegurarnos de que una dependencia que inyectemos en una clase no muestre métodos que no se necesiten o no tengan sentido para lo que pretendemos hacer.\</p> \<p>Por ejemplo, si tenemos una interfaz que define cómo podemos extraer y guardar datos de un sistema de almacenamiento:\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">interface\</span> \<span class="nx">StorageManagerInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">getItems\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">save\</span>\<span class="p">(\</span> \<span class="nx">EntityInterface\</span> \<span class="nv">$item\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>Y tenemos una clase que necesite leer datos de ese sistema para imprimirlos:\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">PrintService\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">printLines\</span>\<span class="p">(\</span> \<span class="nx">StorageManagerInterface\</span> \<span class="nv">$storage\</span> \<span class="p">)\</span> \<span class="p">{\</span> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>Dentro del método printLines no nos interesa guardar nada en el sistema de almacenamiento. De hecho, sería peligroso hacerlo en ese método, ya que se supone que no vamos a hacer ninguna manipulación, sólo deberíamos imprimir los datos que nos traigamos del sistema de almacenamiento.\</p> \<p>Para no saltarnos el principio de Segregación de interfaces, deberíamos separar las operaciones de lectura y escritura en dos interfaces distintas. Si por alguna razón necesitásemos ambas operaciones en alguna clase, podríamos tener otra interfaz que implemente dichas interfaces.\</p> \<p>Nuestro PrintService ahora ya tiene únicamente los métodos que necesita como vemos en el siguiente ejemplo.\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">interface\</span> \<span class="nx">StorageReaderInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">getItems\</span>\<span class="p">();\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">interface\</span> \<span class="nx">StorageeWriterInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">save\</span>\<span class="p">(\</span> \<span class="nx">EntityInterface\</span> \<span class="nv">$entity\</span> \<span class="p">);\</span> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">interface\</span> \<span class="nx">StorageManagerInterface\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">implements\</span> \<span class="nx">StorageReaderInterface\</span>\<span class="p">,\</span> \<span class="nx">StorageWriterInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">PrintService\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="nf">printLines\</span>\<span class="p">(\</span> \<span class="nx">StorageReaderInterface\</span> \<span class="nv">$storage\</span> \<span class="p">)\</span> \<span class="p">{\</span> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<h3 id="dependency-inversion">Dependency inversion\</h3> \<p>La idea de la inversión de dependencias es que nuestro código dependa siempre de abstracciones, no de clases concretas.\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="c1">// incorrecto \</span>\</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">NotificationService\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="fm">\_\_construct\</span>\<span class="p">(\</span> \<span class="nx">EmailSender\</span> \<span class="nv">$sender\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="o">...\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="c1">// correcto \</span>\</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">NotificationService\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="fm">\_\_construct\</span>\<span class="p">(\</span> \<span class="nx">SenderInterface\</span> \<span class="nv">$sender\</span> \<span class="p">)\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="o">...\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>En el ejemplo superior vemos cómo respetar este principio y que al inyectar la interfaz SenderInterface, le damos más flexibilidad pudiendo cambiar en un futuro el tipo de Sender sin tener que modificar el código.\</p> \<p>Sin embargo, pasar una interfaz no es lo único recomendable. Suele ser habitual que utilicemos interfaces de un framework que utilicemos para desarrollar nuestro código.\</p> \<p>Esto nos genera una dependencia con el framework, lo cual puede ser un problema si luego queremos reutilizar código separándolo en un paquete independiente.\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">LoggerService\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="fm">\_\_construct\</span>\<span class="p">(\</span> \<span class="nx">Framework\\EventDispatcherInterface\</span> \<span class="nv">$dispatcher\</span> \<span class="p">)\</span> \<span class="p">{}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\</code>\</pre>\</div>\<p>Lo ideal sería crear nuestra propia interfaz e implementarla en una clase que haga uso de la interfaz que nos provee el framework. Esto nos permite cambiar en un futuro de framework sin que nuestro código se vea afectado.\</p> \<div class="highlight">\<pre tabindex="0" class="chroma">\<code class="language-php" data-lang="php">\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">FrameworkEventDispatcher\</span> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">implements\</span> \<span class="nx">EventDispatcherInterface\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="fm">\_\_construct\</span>\<span class="p">(\</span>\<span class="nx">Framework\\EventDispatcherInterface\</span> \<span class="nv">$dispatcher\</span>\<span class="p">)\</span> \<span class="p">{}\</span> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="k">class\</span> \<span class="nc">LoggerService\</span> \<span class="p">{\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl"> \<span class="k">public\</span> \<span class="k">function\</span> \<span class="fm">\_\_construct\</span>\<span class="p">(\</span> \<span class="nx">EventDispatcherInterface\</span> \<span class="nv">$dispatcher\</span> \<span class="p">)\</span> \<span class="p">{}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="p">}\</span> \</span>\</span>\<span class="line">\<span class="cl"> \</span>\</span>\<span class="line">\<span class="cl">\<span class="nv">$logger\</span> \<span class="o">=\</span> \<span class="k">new\</span> \<span class="nx">LoggerService\</span>\<span class="p">(\</span> \<span class="k">new\</span> \<span class="nx">FrameworkEventDispatcher\</span>\<span class="p">()\</span> \<span class="p">);\</span> \</span>\</span>\</code>\</pre>\</div>\<h3 id="conclusión">Conclusión\</h3> \<p>Los principios SOLID nos permiten diseñar nuestro software para que después de evolucionarlo y mantenerlo durante años no se convierta en una mala partida de Tetris.\</p> \<p>Si tenemos la mente abierta incluso podemos aplicarlos fuera del código o incluso del mundo del software, en otras disciplinas y artes creativas.\</p>

***

## Discussion

No replies yet.
