✅ WEB ja WordPressi uudised, teemad, pistikprogrammid. Siin jagame näpunäiteid ja parimaid veebisaidi lahendusi.

Abstraktsed klassid, 1. osa – Abstraktne käitumine

22

Umbes kuu aega tagasi kirjutasin objektorienteeritud programmeerimise ühest tugisambast (täpsemalt Abstraction). Postituses määratlesin abstraktsiooni järgmiselt:

Selle asemel abstraheerime ideid nende klassidesse. Ja siin on põhiidee: klass peaks esindama nimisõna.

Ja kuigi see on endiselt tõsi, on abstraktsete klasside idee objektorienteeritud programmeerimises midagi muud.

Kõlab segaselt, eks? See on:

  • ühel tasandil on abstraktsioon defineeritud kui idee, et võtame idee ja esindame seda klassis,
  • teisel tasandil on meil abstraktsed klassid, mida kasutatakse funktsioonide määratlemiseks, mida alamklassid peavad rakendama.

Ja kui see ei ole piisavalt segane, segame selle liidestega, mis näevad ette lepingu, millele peavad järgnema rakendamisklassid, ja seejärel abstraktsete klassidega, mis määratlevad meetodid, mida tuleb samuti rakendada, kuid mis võivad rakendada ka oma meetodeid.

Kas olete veel segaduses? Ära muretse. Järgmise kolme postituse mõte on teha järgmist:

  1. Määratlege, mis on abstraktsed klassid,
  2. Kirjeldage abstraktsete klasside ja liideste erinevusi,
  3. Aidake otsustada, millal soovite üht teist kasutada.

Seda öeldes on siin kogu abstraktsete klasside idee.

Abstraheeriv käitumine

Esiteks on erinevus abstraktsioonide ja abstraktsete klasside vahel. Esimene viitab ideele kujutada programmeerimises midagi; viimane viitab tegelikule koodi kirjutamise viisile.

Ja üks parimaid viise, kuidas objektorienteeritud programmeerimise abstraktsetest klassidest mõelda, on mõelda neile järgmiselt:

Abstraktsed klassid asendavad rakendamist.

Võib-olla on veel üks viis neist mõelda kohahoidjatena. Lõppkokkuvõttes pakuvad need käitumist, mida alamklassid peavad rakendama.

Kuidas see erineb liidesest? Pidage meeles, et liides määrab funktsioonile allkirja (funktsiooni nimi, argumendid ja nähtavuse modifikaatorid), mida klass peab rakendama.

Abstraktsioon seevastu asendab teostust, mida alamklass peab rakendama. Kuid võib-olla näitab see kõige paremini koodi kasutamist.

Abstraktsioon praktikas

Oletame, et töötate projekti kallal ja leiate, et teil on funktsioone, mis on olemas rohkem kui ühes kohas. Lisaks kogu DRY idee rikkumisele võib see olla ka koht, kus saate funktsionaalsust põhiklassiks abstraktseks võtta ja seda uuesti kasutada.

Vaatleme seda kirjastamissüsteemi kontekstis. WordPress ei pruugi seda rakendada, kuid see kasutab meile tuttavat ideed: taksonoomiad.

Pidage meeles, et WordPressis on sildid ja kategooriad. Nende kahe vahel on väikesed erinevused (nt kas see on hierarhiline või mitte), kuid neil on ka sarnased atribuudid, nagu nimi ja nälkjas.

Taksonoomia abstraktsioon

Seega võime alustada abstraktse taksonoomia klassi kirjutamisest, mis koondab ühise funktsionaalsuse oma klassi.

<?php

abstract class Taxonomy
{

  private $taxonomyName;

  private $taxonomySlug;

  public function __construct($name) {
    $this->taxonomyName = $name;
    $this->taxonomySlug = strtolower(str_ireplace(' ', '-', $this->taxonomyName));
  }

  public function getName() {
    return $this->taxonomyName;
  }

  public function getSlug() {
    return $this->taxonomySlug;
  }

  abstract protected function isHierarchical();
  abstract protected function isCategory();
  abstract protected function isTag();

}

Ülaltoodud koodis näete, et olen teinud järgmist.

  • kuulutas klassi abstraktseks
  • määratles mitu atribuuti, mis konstruktoris seadistatakse
  • täitnud mitmeid avalikke funktsioone,
  • lisatud mitu kaitstud meetodit.

Selle klassi vaatamise peamine eelis on see, et igal klassil, mis seda abstraktset klassi rakendab, on automaatselt konstruktoris määratletud funktsionaalsus, funktsioon getName ja funktsioon getSlug.

Neil ei ole aga abstraktsete funktsioonide rakendamist. See on see, mis jääb alamklasside rakendada (mida ma kohe jagan).

Konkreetne taksonoomia: silt

Nüüd, kui meil on abstraktne klass määratletud, on võimalik abstraktsiooni ka tegelikult rakendada. Näiteks :

<?php

class Tag extends Taxonomy
{
  protected function isHierarchical() {
    return false;
  }

  protected function isCategory() {
    return $this->isHierarchical;
  }

  protected function isTag() {
    return !$this->isHierarchical;
  }
}

Ülaltoodud koodis pange tähele, et kõik, mida klass teeb, pakub abstraktsetes klassides määratletud abstraktsete funktsioonide realiseerimist (mis on määratud klassi määratluses oleva laiendamisfunktsiooniga).

Hiljem selles artiklis jagan, kuidas seda koodi testida, kuid pange tähele, et ülaltoodu ei paku mitte ainult teile kuvatavaid funktsioone, vaid ka taksonoomiaklassi funktsioone .

Konkreetne taksonoomia: kategooria

Enne kui hakkan seda tegevuses vaatama, tahan määratleda ka kategooria. See hõlmab koodi, mis rakendab abstraktse klassi funktsioone, aga ka oma funktsioone.

Vaata allpool:

<?php
class Category extends Taxonomy
{
  private $parentId = -1;

  protected function isHierarchical() {
    return true;
  }

  protected function isCategory() {
    return $this->isHierarchical;
  }

  protected function isTag() {
    return !$this->isHierarchical;
  }

  public function setParentId($parentId) {
    $this->parentId = $parentId;
  }

  public function getParentId() {
    return $this->parentId;
  }
}

Siin on meil kõik taksonoomiaklassiga kaasnev, kuid oleme määratlenud ka oma atribuudi selle vanema ID ning getter- ja setter-meetodite jaoks. Kuigi antud juhul on see triviaalne, näitab see, kuidas kategooriad, mis on hierarhilised, võivad toimida.

Lisaks, kui kategoorias pole vanemat, määratakse ID väärtuseks -1, mis muudab automaatse testimise jaoks lihtsaks kirjutamise või isegi kontrollimise, kas sellel on ülem.

Nähes seda tegevuses

Kogu selle koodi demonstreerimiseks on mul põhisisu, mis sisaldab kogu koodi ühes failis. Parima tavana ma seda ei soovita. Selle asemel tuleks iga klassi hoida oma failis ja iga klass peaks kuuluma nimeruumi.

Kuid kuna see on puhtalt demonstratsiooni eesmärgil, siis sellest piisab.

<?php

abstract class Taxonomy
{
  private $taxonomyName;

  private $taxonomySlug;

  public function __construct($name) {
    $this->taxonomyName = $name;
    $this->taxonomySlug = strtolower(str_ireplace(' ', '-', $this->taxonomyName));
  }

  public function getName() {
    return $this->taxonomyName;
  }

  public function getSlug() {
    return $this->taxonomySlug;
  }

  abstract protected function isHierarchical();
  abstract protected function isCategory();
  abstract protected function isTag();

}

/*--*/

class Tag extends Taxonomy
{
  protected function isHierarchical() {
    return false;
  }

  protected function isCategory() {
    return $this->isHierarchical;
  }

  protected function isTag() {
    return !$this->isHierarchical;
  }
}

/*--*/

class Category extends Taxonomy
{
  private $parentId = -1;

  protected function isHierarchical() {
    return true;
  }

  protected function isCategory() {
    return $this->isHierarchical;
  }

  protected function isTag() {
    return !$this->isHierarchical;
  }

  public function setParentId($parentId) {
    $this->parentId = $parentId;
  }

  public function getParentId() {
    return $this->parentId;
  }
}

/*- Tag Demo ----------------------------*/

$tag = new Tag('Acme Tag');
echo $tag->getName();
echo $tag->getSlug();

/*- Category Demo -----------------------*/

$category = new Category('Acme Category');

echo $category->getName();
echo $category->getSlug();
echo $category->getParentId();

$category->setParentId(100);
echo $category->getparentId();

Kui käivitate selle konsoolis, peaksite nägema järgmist väljundit:

Võimalik, et peate lisama mõned kajalaused, et veenduda, et see loob uusi ridu, kuid see on teie otsustada.

Aga liidesed?

Niisiis, praegusel hetkel:

  • meil on toimiv määratlus selle kohta, mis on abstraktsed klassid,
  • meil on näide sellest, kuidas abstraktsed klassid välja näevad,
  • ja meil on toimiv demo nende toimimise kohta.

Järgmisena sukeldun sügavamalt abstraktsete klasside ja liideste erinevuste üle, kui soovite võib-olla kasutada ühte või kui soovite neid kasutada koos üksteisega.

See veebisait kasutab teie kasutuskogemuse parandamiseks küpsiseid. Eeldame, et olete sellega rahul, kuid saate soovi korral loobuda. Nõustu Loe rohkem