{"id":229861,"date":"2022-11-22T11:59:00","date_gmt":"2022-11-22T08:59:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=229861"},"modified":"2022-11-22T12:03:03","modified_gmt":"2022-11-22T09:03:03","slug":"clases-abstractas-parte-1-comportamiento-de-abstraccion","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/es\/clases-abstractas-parte-1-comportamiento-de-abstraccion\/","title":{"rendered":"Clases abstractas, Parte 1 &#8211; Comportamiento de abstracci\u00f3n"},"content":{"rendered":"\n<p>Hace aproximadamente un mes, <a href=\"https:\/\/wordpress.mediadoma.com\/es\/los-dos-primeros-pilares-de-la-programacion-orientada-a-objetos\/\" title=\"escrib\u00ed sobre uno\">escrib\u00ed sobre uno<\/a> de los pilares de la programaci\u00f3n orientada a objetos (espec\u00edficamente Abstracci\u00f3n). En la publicaci\u00f3n, defin\u00ed la abstracci\u00f3n de la siguiente manera:<\/p>\n<blockquote>\n<p>En cambio, vamos a abstraer ideas en sus clases. Y aqu\u00ed hay una idea clave: una clase debe representar un sustantivo.<\/p>\n<\/blockquote>\n<p>Y aunque eso sigue siendo cierto, la idea de las <strong>clases abstractas<\/strong> es algo diferente en la programaci\u00f3n orientada a objetos.<\/p>\n<p>Suena confuso, \u00bfverdad? Eso es:<\/p>\n<ul>\n<li>en un nivel, tenemos la abstracci\u00f3n definida como la idea de que tomamos una idea y la representamos en una clase,<\/li>\n<li>en otro nivel, tenemos clases abstractas que se utilizan para ayudar a definir funciones que deben implementar las subclases.<\/li>\n<\/ul>\n<p>Y si eso no es lo suficientemente confuso, mezclamos esto con <a href=\"https:\/\/wordpress.mediadoma.com\/es\/programacion-orientada-a-objetos-comprension-de-las-interfaces\/\" title=\"interfaces\">interfaces<\/a> que proporcionan un contrato que deben seguir las clases de implementaci\u00f3n, y luego lo mezclamos con clases abstractas que definen m\u00e9todos que tambi\u00e9n deben implementarse pero que tambi\u00e9n pueden implementar m\u00e9todos propios.<\/p>\n<p>\u00bfConfundido todav\u00eda? Sin preocupaciones. El objetivo de las pr\u00f3ximas tres publicaciones es hacer lo siguiente:<\/p>\n<ol>\n<li>Definir qu\u00e9 son las clases abstractas,<\/li>\n<li>Describir las diferentes clases e interfaces abstractas,<\/li>\n<li>Ayuda a decidir cu\u00e1ndo quieres usar uno sobre el otro.<\/li>\n<\/ol>\n<p>Dicho esto, aqu\u00ed est\u00e1 toda la idea detr\u00e1s de las clases abstractas.<\/p>\n<h2>Comportamiento de abstracci\u00f3n<\/h2>\n<p>En primer lugar, hay una diferencia en la abstracci\u00f3n y las clases abstractas. El primero se refiere a la idea de representar algo en la programaci\u00f3n; el \u00faltimo se refiere a una forma real de escribir c\u00f3digo.<\/p>\n<p>Y una de las mejores formas que he encontrado para pensar en las clases abstractas en la programaci\u00f3n orientada a objetos es pensar en ellas de esta manera:<\/p>\n<blockquote>\n<p>Las clases abstractas son un sustituto de la implementaci\u00f3n.<\/p>\n<\/blockquote>\n<p>Quiz\u00e1s otra forma de pensar en ellos es como marcadores de posici\u00f3n. En \u00faltima instancia, proporcionan el comportamiento que deben implementar las subclases.<\/p>\n<p>\u00bfEn qu\u00e9 se diferencia esto de una interfaz? Recuerde que una interfaz define una firma para una funci\u00f3n (el nombre de la funci\u00f3n, sus argumentos y sus modificadores de visibilidad) que debe implementar una clase.<\/p>\n<p>La abstracci\u00f3n, por otro lado, proporciona un sustituto para la implementaci\u00f3n que debe implementar una subclase. Pero quiz\u00e1s esto se demuestre mejor mediante el uso de c\u00f3digo.<\/p>\n<h3>Abstracci\u00f3n en la pr\u00e1ctica<\/h3>\n<p>Digamos que est\u00e1 trabajando en un proyecto y descubre que tiene una funcionalidad que existe en m\u00e1s de un lugar. Adem\u00e1s de violar toda la idea de DRY, tambi\u00e9n tiene el potencial de ser un lugar donde puede abstraer la funcionalidad en una clase base y usarla nuevamente.<\/p>\n<p>Consideremos esto en el contexto de un sistema de publicaci\u00f3n. No es necesariamente as\u00ed como WordPress lo implementa, pero usa una idea con la que estamos familiarizados: las taxonom\u00edas.<\/p>\n<p>En WordPress, recuerda que tenemos <strong>Etiquetas<\/strong> y <strong>Categor\u00edas<\/strong>. Hay diferencias sutiles entre los dos (como si uno es jer\u00e1rquico o no), pero tambi\u00e9n comparten atributos similares, como tener un nombre y un slug.<\/p>\n<h3>Una abstracci\u00f3n taxon\u00f3mica<\/h3>\n<p>Entonces, podemos comenzar escribiendo una clase de taxonom\u00eda abstracta que abstraiga la funcionalidad com\u00fan <a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-00-taxonomy-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">en su propia clase.<\/a><\/p>\n<pre><code>&lt;?php\n\nabstract class Taxonomy\n{\n\n  private $taxonomyName;\n\n  private $taxonomySlug;\n\n  public function __construct($name) {\n    $this-&gt;taxonomyName = $name;\n    $this-&gt;taxonomySlug = strtolower(str_ireplace(' ', '-', $this-&gt;taxonomyName));\n  }\n\n  public function getName() {\n    return $this-&gt;taxonomyName;\n  }\n\n  public function getSlug() {\n    return $this-&gt;taxonomySlug;\n  }\n\n  abstract protected function isHierarchical();\n  abstract protected function isCategory();\n  abstract protected function isTag();\n\n}<\/code><\/pre>\n<p>En el c\u00f3digo anterior, ver\u00e1 que he hecho lo siguiente:<\/p>\n<ul>\n<li>declar\u00f3 la clase <strong>abstracta<\/strong><\/li>\n<li>defini\u00f3 varios atributos que se establecer\u00e1n en el constructor<\/li>\n<li>proporcion\u00f3 varias funciones p\u00fablicas con la implementaci\u00f3n,<\/li>\n<li>agreg\u00f3 varios m\u00e9todos protegidos.<\/li>\n<\/ul>\n<p>La conclusi\u00f3n clave al observar esta clase es que cualquier clase que implemente esta clase abstracta tendr\u00e1 autom\u00e1ticamente la funcionalidad definida en el constructor, la funci\u00f3n <strong>getName<\/strong> y la funci\u00f3n <strong>getSlug<\/strong>.<\/p>\n<p>Sin embargo, no tendr\u00e1n la implementaci\u00f3n de las funciones <strong>abstractas<\/strong>. Eso es lo que queda para ser implementado por las subclases (que compartir\u00e9 moment\u00e1neamente).<\/p>\n<h3>Una taxonom\u00eda concreta: una etiqueta<\/h3>\n<p>Ahora que tenemos una clase abstracta definida, es posible implementar la abstracci\u00f3n. <a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-01-tag-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Por ejemplo<\/a> :<\/p>\n<pre><code>&lt;?php\n\nclass Tag extends Taxonomy\n{\n  protected function isHierarchical() {\n    return false;\n  }\n\n  protected function isCategory() {\n    return $this-&gt;isHierarchical;\n  }\n\n  protected function isTag() {\n    return !$this-&gt;isHierarchical;\n  }\n}\n<\/code><\/pre>\n<p>En el c\u00f3digo anterior, observe que todo lo que hace la clase es proporcionar la implementaci\u00f3n de las funciones abstractas definidas en la clase abstracta (que se especifica mediante la funci\u00f3n <strong>extends<\/strong> en la definici\u00f3n de clase).<\/p>\n<p>M\u00e1s adelante en este art\u00edculo, compartir\u00e9 c\u00f3mo probar este c\u00f3digo, pero tenga en cuenta que lo anterior no solo ofrece la funcionalidad que ve, sino tambi\u00e9n la funcionalidad de la clase <strong>Taxonomy<\/strong>.<\/p>\n<h3>Una taxonom\u00eda concreta: una categor\u00eda<\/h3>\n<p>Antes de echar un vistazo a esto en acci\u00f3n, tambi\u00e9n quiero definir una categor\u00eda. Esto incluir\u00e1 c\u00f3digo que implemente funciones de la clase abstracta pero tambi\u00e9n funciones propias.<\/p>\n<p><a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-02-category-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Vea abajo:<\/a><\/p>\n<pre><code>&lt;?php\nclass Category extends Taxonomy\n{\n  private $parentId = -1;\n\n  protected function isHierarchical() {\n    return true;\n  }\n\n  protected function isCategory() {\n    return $this-&gt;isHierarchical;\n  }\n\n  protected function isTag() {\n    return !$this-&gt;isHierarchical;\n  }\n\n  public function setParentId($parentId) {\n    $this-&gt;parentId = $parentId;\n  }\n\n  public function getParentId() {\n    return $this-&gt;parentId;\n  }\n}\n<\/code><\/pre>\n<p>Aqu\u00ed tenemos todo lo que viene con la clase <strong>Taxonomy<\/strong>, pero tambi\u00e9n hemos definido nuestra propiedad para su ID principal y m\u00e9todos getter y setter. Aunque trivial en este caso, muestra c\u00f3mo pueden funcionar las categor\u00edas, que son jer\u00e1rquicas.<\/p>\n<p>Adem\u00e1s, si la categor\u00eda no tiene un padre, entonces la ID se establece en -1, lo que facilita la escritura para pruebas automatizadas o incluso verificar si tiene un padre.<\/p>\n<h3>Verlo en acci\u00f3n<\/h3>\n<p>Para hacer una demostraci\u00f3n de todo este c\u00f3digo, tengo una idea general que incluye todo el c\u00f3digo en un solo archivo. Como mejor pr\u00e1ctica, no recomiendo esto. En su lugar, cada clase debe mantenerse en su propio archivo y cada clase debe pertenecer a un espacio de nombres.<\/p>\n<p>Pero dado que esto es puramente para fines de demostraci\u00f3n, <a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-03-demo-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">es suficiente.<\/a><\/p>\n<pre><code>&lt;?php\n\nabstract class Taxonomy\n{\n  private $taxonomyName;\n\n  private $taxonomySlug;\n\n  public function __construct($name) {\n    $this-&gt;taxonomyName = $name;\n    $this-&gt;taxonomySlug = strtolower(str_ireplace(' ', '-', $this-&gt;taxonomyName));\n  }\n\n  public function getName() {\n    return $this-&gt;taxonomyName;\n  }\n\n  public function getSlug() {\n    return $this-&gt;taxonomySlug;\n  }\n\n  abstract protected function isHierarchical();\n  abstract protected function isCategory();\n  abstract protected function isTag();\n\n}\n\n\/*--*\/\n\nclass Tag extends Taxonomy\n{\n  protected function isHierarchical() {\n    return false;\n  }\n\n  protected function isCategory() {\n    return $this-&gt;isHierarchical;\n  }\n\n  protected function isTag() {\n    return !$this-&gt;isHierarchical;\n  }\n}\n\n\/*--*\/\n\nclass Category extends Taxonomy\n{\n  private $parentId = -1;\n\n  protected function isHierarchical() {\n    return true;\n  }\n\n  protected function isCategory() {\n    return $this-&gt;isHierarchical;\n  }\n\n  protected function isTag() {\n    return !$this-&gt;isHierarchical;\n  }\n\n  public function setParentId($parentId) {\n    $this-&gt;parentId = $parentId;\n  }\n\n  public function getParentId() {\n    return $this-&gt;parentId;\n  }\n}\n\n\/*- Tag Demo ----------------------------*\/\n\n$tag = new Tag('Acme Tag');\necho $tag-&gt;getName();\necho $tag-&gt;getSlug();\n\n\/*- Category Demo -----------------------*\/\n\n$category = new Category('Acme Category');\n\necho $category-&gt;getName();\necho $category-&gt;getSlug();\necho $category-&gt;getParentId();\n\n$category-&gt;setParentId(100);\necho $category-&gt;getparentId();\n<\/code><\/pre>\n<p>Cuando ejecute esto en la consola, deber\u00eda ver algo como el siguiente resultado:<\/p>\n<p>Es posible que deba agregar algunas declaraciones de <strong>eco<\/strong> para asegurarse de que est\u00e1 creando nuevas l\u00edneas, pero eso depende de usted.<\/p>\n<h2>\u00bfQu\u00e9 pasa con las interfaces?<\/h2>\n<p>Entonces, en este punto:<\/p>\n<ul>\n<li>tenemos una definici\u00f3n funcional de lo que son las clases abstractas,<\/li>\n<li>tenemos un ejemplo de c\u00f3mo se ven las clases abstractas,<\/li>\n<li>y tenemos una demostraci\u00f3n funcional de c\u00f3mo pueden funcionar.<\/li>\n<\/ul>\n<p>A continuaci\u00f3n, me sumergir\u00e9 m\u00e1s profundamente en la discusi\u00f3n de las diferencias entre las clases abstractas y las interfaces, cu\u00e1ndo puede querer usar una sobre la otra o cu\u00e1ndo puede querer usarlas en conjunto.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fuente de grabaci\u00f3n:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/tommcfarlin.com\" class=\"external external_icon\">tommcfarlin.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Abstraer el comportamiento es fundamental en la programaci\u00f3n orientada a objetos, pero comprender c\u00f3mo hacerlo es importante.<\/p>\n","protected":false},"author":1,"featured_media":164837,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[892,716,914,800,840],"tags":[1172],"class_list":["post-229861","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-codigo","category-desarrollador","category-otro","category-php-2","category-tutoriales","tag-affiai-es"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/229861","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/comments?post=229861"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/posts\/229861\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media\/164837"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/media?parent=229861"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/categories?post=229861"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/es\/wp-json\/wp\/v2\/tags?post=229861"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}