✅ Notícias, temas e plug-ins da WEB e do WordPress. Aqui compartilhamos dicas e as melhores soluções para sites.

Aulas de Resumo, Parte 1 – Comportamento de Abstração

18

Cerca de um mês atrás, escrevi sobre um dos pilares da programação orientada a objetos (especificamente a abstração). No post, defini abstração como o seguinte:

Em vez disso, vamos abstrair ideias em suas classes. E há uma ideia chave aqui: uma classe deve representar um substantivo.

E embora isso ainda seja verdade, a ideia de classes abstratas é algo diferente na programação orientada a objetos.

Parece confuso, certo? Aquilo é:

  • em um nível, temos abstração sendo definida como a ideia de que pegamos uma ideia e a representamos em uma classe,
  • em outro nível, temos classes abstratas que são usadas para ajudar a definir funções que as subclasses devem implementar.

E se isso não for confuso o suficiente, misturamos isso com interfaces que fornecem um contrato de implementação de classes que deve seguir, e então misturamos com classes abstratas que definem métodos que também devem ser implementados, mas também podem implementar métodos próprios.

Confuso ainda? Sem problemas. O objetivo dos próximos três posts é fazer o seguinte:

  1. Defina o que são classes abstratas,
  2. Descrever o diferente em classes abstratas e interfaces,
  3. Ajude a decidir quando você quer usar um sobre o outro.

Com isso dito, aqui está toda a ideia por trás das classes abstratas.

Comportamento de abstração

Em primeiro lugar, há uma diferença na abstração e nas classes abstratas. A primeira refere-se à ideia de representar algo na programação; o último refere-se a uma maneira real de escrever código.

E uma das melhores maneiras que encontrei para pensar sobre classes abstratas na programação orientada a objetos é pensar nelas assim:

As classes abstratas são um substituto para a implementação.

Talvez outra maneira de pensar neles seja como espaços reservados. Em última análise, eles fornecem o comportamento que as subclasses devem implementar.

Como isso é diferente de uma interface? Lembre-se de que uma interface define uma assinatura para uma função (o nome da função, seus argumentos e seus modificadores de visibilidade) que uma classe deve implementar.

A abstração, por outro lado, fornece um substituto para a implementação que uma subclasse deve implementar. Mas talvez isso seja melhor demonstrado através do uso de código.

Abstração na prática

Digamos que você esteja trabalhando em um projeto e descubra que tem uma funcionalidade que existe em mais de um lugar. Além de violar toda a ideia de DRY, ele também tem potencial para ser um lugar onde você pode abstrair a funcionalidade em uma classe base e usá-la novamente.

Vamos considerar isso no contexto de um sistema de publicação. Não é necessariamente assim que o WordPress o implementa, mas usa uma ideia com a qual estamos familiarizados: Taxonomias.

No WordPress, lembre-se que temos Tags e Categorias. Existem diferenças sutis entre os dois (como se um é hierárquico ou não), mas eles também compartilham atributos semelhantes, como ter um nome e um slug.

Uma Abstração de Taxonomia

Assim, podemos começar escrevendo uma classe abstrata de Taxonomia que abstrai a funcionalidade comum em sua própria classe.

<?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();

}

No código acima, você verá que fiz o seguinte:

  • declarou o resumo da classe
  • definiu vários atributos que serão definidos no construtor
  • desde várias funções públicas com implementação,
  • adicionou vários métodos protegidos.

A principal vantagem de olhar para essa classe é que qualquer classe que implemente essa classe abstrata terá automaticamente a funcionalidade definida no construtor, na função getName e na função getSlug.

Eles não terão, no entanto, a implementação das funções abstratas. Isso é o que resta para ser implementado pelas subclasses (que compartilharei momentaneamente).

Uma taxonomia concreta: uma etiqueta

Agora que temos uma classe abstrata definida, é possível realmente implementar a abstração. Por exemplo :

<?php

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

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

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

No código acima, observe que tudo que a classe faz é fornecer a implementação para as funções abstratas definidas na classe abstrata (que é especificada pela função extends na definição da classe).

Mais adiante neste artigo, compartilharei como testar esse código, mas observe que o acima não apenas oferece a funcionalidade que você vê, mas também a funcionalidade da classe Taxonomy.

Uma taxonomia concreta: uma categoria

Antes de dar uma olhada nisso em ação, quero definir uma categoria também. Isso incluirá código que implementa funções da classe abstrata, mas também funções próprias.

Veja abaixo:

<?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;
  }
}

Aqui, temos tudo que vem com a classe Taxonomy, mas também definimos nossa propriedade para seu ID pai e métodos getter e setter. Embora trivial neste caso, mostra como as categorias, que são hierárquicas, podem funcionar.

Além disso, se a categoria não tiver pai, o ID será definido como -1, o que facilita a gravação para testes automatizados ou até mesmo verificar se tem um pai.

Vendo isso em ação

Para demonstrar todo esse código, tenho uma essência que inclui todo o código em um único arquivo. Como prática recomendada, não recomendo isso. Em vez disso, cada classe deve ser mantida em seu próprio arquivo e cada classe deve pertencer a um namespace.

Mas como isso é puramente para fins de demonstração, é suficiente.

<?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();

Ao executar isso no console, você deverá ver algo como a seguinte saída:

Você pode precisar adicionar algumas declarações de eco para ter certeza de que está criando novas linhas, mas isso é com você.

E as interfaces?

Então, neste momento:

  • temos uma definição funcional do que são classes abstratas,
  • temos um exemplo de como são as classes abstratas,
  • e temos uma demonstração funcional de como eles podem funcionar.

Em seguida, vou me aprofundar na discussão das diferenças entre classes abstratas e interfaces, quando você pode querer usar uma sobre a outra, ou quando você pode querer usá-las em conjunto.

Fonte de gravação: tommcfarlin.com

Este site usa cookies para melhorar sua experiência. Presumiremos que você está ok com isso, mas você pode cancelar, se desejar. Aceitar Consulte Mais informação