{"id":229531,"date":"2022-11-22T11:57:00","date_gmt":"2022-11-22T08:57:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=229531"},"modified":"2022-11-09T08:20:58","modified_gmt":"2022-11-09T05:20:58","slug":"klasy-abstrakcyjne-czesc-1-zachowanie-abstrakcji","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pl\/klasy-abstrakcyjne-czesc-1-zachowanie-abstrakcji\/","title":{"rendered":"Klasy abstrakcyjne, cz\u0119\u015b\u0107 1 \u2014 zachowanie abstrakcji"},"content":{"rendered":"\n<p>Oko\u0142o miesi\u0105c temu <a href=\"https:\/\/tommcfarlin.com\/two-pillars-of-object-oriented-programming-1\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">pisa\u0142em o jednym<\/a> z filar\u00f3w programowania obiektowego (a konkretnie o abstrakcji). W po\u015bcie zdefiniowa\u0142em abstrakcj\u0119 jako:<\/p>\n<blockquote>\n<p>Zamiast tego b\u0119dziemy abstrahowa\u0107 pomys\u0142y do \u200b\u200bich klas. I tutaj jest kluczowa idea: klasa powinna reprezentowa\u0107 rzeczownik.<\/p>\n<\/blockquote>\n<p>I cho\u0107 to wci\u0105\u017c prawda, idea <strong>klas abstrakcyjnych<\/strong> jest czym\u015b innym w programowaniu obiektowym.<\/p>\n<p>Brzmi dezorientuj\u0105co, prawda? To znaczy:<\/p>\n<ul>\n<li>na jednym poziomie mamy abstrakcj\u0119 definiowan\u0105 jako pomys\u0142, \u017ce bierzemy ide\u0119 i reprezentujemy j\u0105 w klasie,<\/li>\n<li>na innym poziomie mamy klasy abstrakcyjne, kt\u00f3re pomagaj\u0105 zdefiniowa\u0107 funkcje, kt\u00f3re musz\u0105 zaimplementowa\u0107 podklasy.<\/li>\n<\/ul>\n<p>A je\u015bli to nie jest wystarczaj\u0105co zagmatwane, mieszamy to z <a href=\"https:\/\/tommcfarlin.com\/understanding-interfaces\/\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">interfejsami,<\/a> kt\u00f3re dostarczaj\u0105 kontraktu, kt\u00f3re musz\u0105 nast\u0119powa\u0107, a nast\u0119pnie mieszamy z klasami abstrakcyjnymi, kt\u00f3re definiuj\u0105 metody, kt\u00f3re r\u00f3wnie\u017c musz\u0105 by\u0107 zaimplementowane, ale mog\u0105 r\u00f3wnie\u017c implementowa\u0107 w\u0142asne metody.<\/p>\n<p>Zdezorientowany? Bez obaw. Celem kolejnych trzech post\u00f3w jest wykonanie nast\u0119puj\u0105cych czynno\u015bci:<\/p>\n<ol>\n<li>Zdefiniuj czym s\u0105 klasy abstrakcyjne,<\/li>\n<li>Opisz r\u00f3\u017cnice w klasach abstrakcyjnych i interfejsach,<\/li>\n<li>Pom\u00f3\u017c zdecydowa\u0107, kiedy chcesz u\u017cy\u0107 jednego z drugim.<\/li>\n<\/ol>\n<p>Powiedziawszy to, oto ca\u0142a idea klas abstrakcyjnych.<\/p>\n<h2>Abstrakcyjne zachowanie<\/h2>\n<p>Przede wszystkim istnieje r\u00f3\u017cnica w klasach abstrakcyjnych i abstrakcyjnych. Pierwsza odnosi si\u0119 do idei reprezentowania czego\u015b w programowaniu; to ostatnie odnosi si\u0119 do rzeczywistego sposobu pisania kodu.<\/p>\n<p>A jednym z najlepszych sposob\u00f3w, jakie znalaz\u0142em na my\u015blenie o klasach abstrakcyjnych w programowaniu obiektowym, jest my\u015blenie o nich w nast\u0119puj\u0105cy spos\u00f3b:<\/p>\n<blockquote>\n<p>Klasy abstrakcyjne s\u0105 substytutem implementacji.<\/p>\n<\/blockquote>\n<p>By\u0107 mo\u017ce innym sposobem my\u015blenia o nich s\u0105 symbole zast\u0119pcze. Ostatecznie zapewniaj\u0105 zachowanie, kt\u00f3re podklasy musz\u0105 zaimplementowa\u0107.<\/p>\n<p>Czym to si\u0119 r\u00f3\u017cni od interfejsu? Pami\u0119taj, \u017ce interfejs definiuje sygnatur\u0119 funkcji (nazw\u0119 funkcji, jej argumenty i jej modyfikatory widoczno\u015bci), kt\u00f3r\u0105 klasa musi zaimplementowa\u0107.<\/p>\n<p>Z drugiej strony abstrakcja zapewnia substytut implementacji, kt\u00f3r\u0105 musi zaimplementowa\u0107 podklasa. Ale by\u0107 mo\u017ce najlepiej jest to zademonstrowa\u0107 za pomoc\u0105 kodu.<\/p>\n<h3>Abstrakcja w praktyce<\/h3>\n<p>Za\u0142\u00f3\u017cmy, \u017ce pracujesz nad projektem i odkrywasz, \u017ce masz funkcjonalno\u015b\u0107, kt\u00f3ra istnieje w wi\u0119cej ni\u017c jednym miejscu. Opr\u00f3cz naruszania ca\u0142ej idei DRY, ma r\u00f3wnie\u017c potencja\u0142, aby by\u0107 miejscem, w kt\u00f3rym mo\u017cna wyabstrahowa\u0107 funkcjonalno\u015b\u0107 do klasy bazowej i u\u017cy\u0107 jej ponownie.<\/p>\n<p>Rozwa\u017cmy to w kontek\u015bcie systemu wydawniczego. Niekoniecznie w taki spos\u00f3b implementuje go WordPress, ale wykorzystuje ide\u0119, kt\u00f3r\u0105 znamy: taksonomie.<\/p>\n<p>W WordPressie przypomnij sobie, \u017ce mamy <strong>Tagi<\/strong> i <strong>kategorie<\/strong>. Istniej\u0105 subtelne r\u00f3\u017cnice mi\u0119dzy tymi dwoma (na przyk\u0142ad, czy jeden, je\u015bli jest hierarchiczny, czy nie), ale maj\u0105 r\u00f3wnie\u017c podobne atrybuty, takie jak posiadanie imienia i \u015blimaka.<\/p>\n<h3>Abstrakcja taksonomiczna<\/h3>\n<p>Mo\u017cemy wi\u0119c zacz\u0105\u0107 od napisania abstrakcyjnej klasy Taxonomy, kt\u00f3ra abstrahuje wsp\u00f3ln\u0105 funkcjonalno\u015b\u0107 <a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-00-taxonomy-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">do w\u0142asnej klasy.<\/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>W powy\u017cszym kodzie zobaczysz, \u017ce wykona\u0142em nast\u0119puj\u0105ce czynno\u015bci:<\/p>\n<ul>\n<li><strong>zadeklarowa\u0142 abstrakt<\/strong> klasy<\/li>\n<li>zdefiniowa\u0142 kilka atrybut\u00f3w, kt\u00f3re zostan\u0105 ustawione w konstruktorze<\/li>\n<li>realizowa\u0142 kilka funkcji publicznych,<\/li>\n<li>dodano kilka chronionych metod.<\/li>\n<\/ul>\n<p>Kluczem od spojrzenia na t\u0119 klas\u0119 jest to, \u017ce ka\u017cda klasa, kt\u00f3ra implementuje t\u0119 klas\u0119 abstrakcyjn\u0105, automatycznie b\u0119dzie mia\u0142a funkcjonalno\u015b\u0107 zdefiniowan\u0105 w konstruktorze, funkcji <strong>getName<\/strong> i funkcji <strong>getSlug<\/strong>.<\/p>\n<p>Nie b\u0119d\u0105 jednak mia\u0142y implementacji funkcji <strong>abstrakcyjnych<\/strong>. To jest to, co pozosta\u0142o do zaimplementowania przez podklasy (kt\u00f3re za chwil\u0119 udost\u0119pni\u0119).<\/p>\n<h3>Konkretna taksonomia: tag<\/h3>\n<p>Teraz, gdy mamy zdefiniowan\u0105 klas\u0119 abstrakcyjn\u0105, mo\u017cna faktycznie zaimplementowa\u0107 abstrakcj\u0119. <a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-01-tag-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Na przyk\u0142ad<\/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>Zauwa\u017c, \u017ce w powy\u017cszym kodzie klasa zapewnia implementacj\u0119 funkcji abstrakcyjnych zdefiniowanych w klasie abstrakcyjnej (co jest okre\u015blone przez funkcj\u0119 <strong>extends<\/strong> w definicji klasy).<\/p>\n<p>W dalszej cz\u0119\u015bci tego artyku\u0142u podziel\u0119 si\u0119, jak przetestowa\u0107 ten kod, ale zauwa\u017c, \u017ce powy\u017csze nie tylko oferuje funkcjonalno\u015b\u0107, kt\u00f3r\u0105 widzisz, ale tak\u017ce funkcjonalno\u015b\u0107 klasy <strong>Taxonomy .<\/strong><\/p>\n<h3>Konkretna taksonomia: kategoria<\/h3>\n<p>Zanim przyjrz\u0119 si\u0119 temu w akcji, chc\u0119 r\u00f3wnie\u017c zdefiniowa\u0107 kategori\u0119. Obejmuje to kod, kt\u00f3ry implementuje funkcje z klasy abstrakcyjnej, ale tak\u017ce funkcje w\u0142asne.<\/p>\n<p><a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-02-category-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">Zobacz poni\u017cej:<\/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>Tutaj mamy wszystko, co pochodzi z klasy <strong>Taxonomy<\/strong>, ale zdefiniowali\u015bmy r\u00f3wnie\u017c nasz\u0105 w\u0142a\u015bciwo\u015b\u0107 dla jej identyfikatora rodzica oraz metod pobieraj\u0105cych i ustawiaj\u0105cych. Cho\u0107 w tym przypadku banalna, pokazuje, jak mog\u0105 funkcjonowa\u0107 kategorie, kt\u00f3re s\u0105 hierarchiczne.<\/p>\n<p>Ponadto, je\u015bli kategoria nie ma rodzica, identyfikator jest ustawiony na -1, co u\u0142atwia pisanie do automatycznego testowania, a nawet sprawdzanie, czy ma rodzica.<\/p>\n<h3>Widz\u0105c to w akcji<\/h3>\n<p>Aby zademonstrowa\u0107 ca\u0142y kod, mam sedno, kt\u00f3re zawiera ca\u0142y kod w jednym pliku. Jako najlepsza praktyka nie polecam tego. Zamiast tego ka\u017cda klasa powinna by\u0107 przechowywana w osobnym pliku, a ka\u017cda klasa powinna nale\u017ce\u0107 do przestrzeni nazw.<\/p>\n<p>Ale poniewa\u017c s\u0142u\u017cy to wy\u0142\u0105cznie celom demonstracyjnym, <a href=\"https:\/\/gist.github.com\/tommcfarlin\/5b2936875807f041e98a87f8a5627e8b#file-03-demo-php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">wystarczy.<\/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>Po uruchomieniu tego w konsoli powiniene\u015b zobaczy\u0107 co\u015b takiego jak nast\u0119puj\u0105ce dane wyj\u015bciowe:<\/p>\n<p>By\u0107 mo\u017ce b\u0119dziesz musia\u0142 doda\u0107 kilka stwierdze\u0144 <strong>echa<\/strong>, aby upewni\u0107 si\u0119, \u017ce tworzy nowe linie, ale to zale\u017cy od Ciebie.<\/p>\n<h2>A co z interfejsami?<\/h2>\n<p>W tym momencie:<\/p>\n<ul>\n<li>mamy robocz\u0105 definicj\u0119 tego, czym s\u0105 klasy abstrakcyjne,<\/li>\n<li>mamy przyk\u0142ad jak wygl\u0105daj\u0105 klasy abstrakcyjne,<\/li>\n<li>i mamy dzia\u0142aj\u0105ce demo tego, jak mog\u0105 dzia\u0142a\u0107.<\/li>\n<\/ul>\n<p>Nast\u0119pnie zag\u0142\u0119bi\u0119 si\u0119 w om\u00f3wienie r\u00f3\u017cnic mi\u0119dzy klasami abstrakcyjnymi a interfejsami, kiedy mo\u017cesz chcie\u0107 u\u017cy\u0107 jednego z drugim lub kiedy mo\u017cesz chcie\u0107 u\u017cy\u0107 ich w po\u0142\u0105czeniu ze sob\u0105.<\/p>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">\u0179r\u00f3d\u0142o nagrywania:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/tommcfarlin.com\" class=\"external external_icon\">tommcfarlin.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Abstrakcyjne zachowanie ma kluczowe znaczenie w programowaniu obiektowym, ale wa\u017cne jest zrozumienie, jak to zrobi\u0107.<\/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":[721,919,897,805,845],"tags":[1169],"class_list":["post-229531","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-deweloper","category-inny","category-kod","category-php-7","category-samouczki","tag-affiai-pl"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/229531","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/comments?post=229531"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/posts\/229531\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media\/164837"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/media?parent=229531"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/categories?post=229531"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pl\/wp-json\/wp\/v2\/tags?post=229531"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}